162306a36Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation 462306a36Sopenharmony_ci * Copyright (c) 2016-2017 Broadcom Limited 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 862306a36Sopenharmony_ci * the Free Software Foundation. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/ctype.h> 1262306a36Sopenharmony_ci#include <linux/stringify.h> 1362306a36Sopenharmony_ci#include <linux/ethtool.h> 1462306a36Sopenharmony_ci#include <linux/ethtool_netlink.h> 1562306a36Sopenharmony_ci#include <linux/linkmode.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/pci.h> 1862306a36Sopenharmony_ci#include <linux/etherdevice.h> 1962306a36Sopenharmony_ci#include <linux/crc32.h> 2062306a36Sopenharmony_ci#include <linux/firmware.h> 2162306a36Sopenharmony_ci#include <linux/utsname.h> 2262306a36Sopenharmony_ci#include <linux/time.h> 2362306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 2462306a36Sopenharmony_ci#include <linux/net_tstamp.h> 2562306a36Sopenharmony_ci#include <linux/timecounter.h> 2662306a36Sopenharmony_ci#include <net/netlink.h> 2762306a36Sopenharmony_ci#include "bnxt_hsi.h" 2862306a36Sopenharmony_ci#include "bnxt.h" 2962306a36Sopenharmony_ci#include "bnxt_hwrm.h" 3062306a36Sopenharmony_ci#include "bnxt_ulp.h" 3162306a36Sopenharmony_ci#include "bnxt_xdp.h" 3262306a36Sopenharmony_ci#include "bnxt_ptp.h" 3362306a36Sopenharmony_ci#include "bnxt_ethtool.h" 3462306a36Sopenharmony_ci#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ 3562306a36Sopenharmony_ci#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ 3662306a36Sopenharmony_ci#include "bnxt_coredump.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define BNXT_NVM_ERR_MSG(dev, extack, msg) \ 3962306a36Sopenharmony_ci do { \ 4062306a36Sopenharmony_ci if (extack) \ 4162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, msg); \ 4262306a36Sopenharmony_ci netdev_err(dev, "%s\n", msg); \ 4362306a36Sopenharmony_ci } while (0) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic u32 bnxt_get_msglevel(struct net_device *dev) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return bp->msg_enable; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void bnxt_set_msglevel(struct net_device *dev, u32 value) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci bp->msg_enable = value; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int bnxt_get_coalesce(struct net_device *dev, 6062306a36Sopenharmony_ci struct ethtool_coalesce *coal, 6162306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 6262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 6562306a36Sopenharmony_ci struct bnxt_coal *hw_coal; 6662306a36Sopenharmony_ci u16 mult; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci memset(coal, 0, sizeof(*coal)); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci hw_coal = &bp->rx_coal; 7362306a36Sopenharmony_ci mult = hw_coal->bufs_per_record; 7462306a36Sopenharmony_ci coal->rx_coalesce_usecs = hw_coal->coal_ticks; 7562306a36Sopenharmony_ci coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; 7662306a36Sopenharmony_ci coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 7762306a36Sopenharmony_ci coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 7862306a36Sopenharmony_ci if (hw_coal->flags & 7962306a36Sopenharmony_ci RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 8062306a36Sopenharmony_ci kernel_coal->use_cqe_mode_rx = true; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci hw_coal = &bp->tx_coal; 8362306a36Sopenharmony_ci mult = hw_coal->bufs_per_record; 8462306a36Sopenharmony_ci coal->tx_coalesce_usecs = hw_coal->coal_ticks; 8562306a36Sopenharmony_ci coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; 8662306a36Sopenharmony_ci coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 8762306a36Sopenharmony_ci coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 8862306a36Sopenharmony_ci if (hw_coal->flags & 8962306a36Sopenharmony_ci RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 9062306a36Sopenharmony_ci kernel_coal->use_cqe_mode_tx = true; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int bnxt_set_coalesce(struct net_device *dev, 9862306a36Sopenharmony_ci struct ethtool_coalesce *coal, 9962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 10062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 10362306a36Sopenharmony_ci bool update_stats = false; 10462306a36Sopenharmony_ci struct bnxt_coal *hw_coal; 10562306a36Sopenharmony_ci int rc = 0; 10662306a36Sopenharmony_ci u16 mult; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (coal->use_adaptive_rx_coalesce) { 10962306a36Sopenharmony_ci bp->flags |= BNXT_FLAG_DIM; 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_DIM) { 11262306a36Sopenharmony_ci bp->flags &= ~(BNXT_FLAG_DIM); 11362306a36Sopenharmony_ci goto reset_coalesce; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && 11862306a36Sopenharmony_ci !(bp->coal_cap.cmpl_params & 11962306a36Sopenharmony_ci RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) 12062306a36Sopenharmony_ci return -EOPNOTSUPP; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci hw_coal = &bp->rx_coal; 12362306a36Sopenharmony_ci mult = hw_coal->bufs_per_record; 12462306a36Sopenharmony_ci hw_coal->coal_ticks = coal->rx_coalesce_usecs; 12562306a36Sopenharmony_ci hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; 12662306a36Sopenharmony_ci hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; 12762306a36Sopenharmony_ci hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; 12862306a36Sopenharmony_ci hw_coal->flags &= 12962306a36Sopenharmony_ci ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 13062306a36Sopenharmony_ci if (kernel_coal->use_cqe_mode_rx) 13162306a36Sopenharmony_ci hw_coal->flags |= 13262306a36Sopenharmony_ci RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci hw_coal = &bp->tx_coal; 13562306a36Sopenharmony_ci mult = hw_coal->bufs_per_record; 13662306a36Sopenharmony_ci hw_coal->coal_ticks = coal->tx_coalesce_usecs; 13762306a36Sopenharmony_ci hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; 13862306a36Sopenharmony_ci hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; 13962306a36Sopenharmony_ci hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; 14062306a36Sopenharmony_ci hw_coal->flags &= 14162306a36Sopenharmony_ci ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 14262306a36Sopenharmony_ci if (kernel_coal->use_cqe_mode_tx) 14362306a36Sopenharmony_ci hw_coal->flags |= 14462306a36Sopenharmony_ci RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { 14762306a36Sopenharmony_ci u32 stats_ticks = coal->stats_block_coalesce_usecs; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Allow 0, which means disable. */ 15062306a36Sopenharmony_ci if (stats_ticks) 15162306a36Sopenharmony_ci stats_ticks = clamp_t(u32, stats_ticks, 15262306a36Sopenharmony_ci BNXT_MIN_STATS_COAL_TICKS, 15362306a36Sopenharmony_ci BNXT_MAX_STATS_COAL_TICKS); 15462306a36Sopenharmony_ci stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); 15562306a36Sopenharmony_ci bp->stats_coal_ticks = stats_ticks; 15662306a36Sopenharmony_ci if (bp->stats_coal_ticks) 15762306a36Sopenharmony_ci bp->current_interval = 15862306a36Sopenharmony_ci bp->stats_coal_ticks * HZ / 1000000; 15962306a36Sopenharmony_ci else 16062306a36Sopenharmony_ci bp->current_interval = BNXT_TIMER_INTERVAL; 16162306a36Sopenharmony_ci update_stats = true; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cireset_coalesce: 16562306a36Sopenharmony_ci if (test_bit(BNXT_STATE_OPEN, &bp->state)) { 16662306a36Sopenharmony_ci if (update_stats) { 16762306a36Sopenharmony_ci bnxt_close_nic(bp, true, false); 16862306a36Sopenharmony_ci rc = bnxt_open_nic(bp, true, false); 16962306a36Sopenharmony_ci } else { 17062306a36Sopenharmony_ci rc = bnxt_hwrm_set_coal(bp); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return rc; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const char * const bnxt_ring_rx_stats_str[] = { 17862306a36Sopenharmony_ci "rx_ucast_packets", 17962306a36Sopenharmony_ci "rx_mcast_packets", 18062306a36Sopenharmony_ci "rx_bcast_packets", 18162306a36Sopenharmony_ci "rx_discards", 18262306a36Sopenharmony_ci "rx_errors", 18362306a36Sopenharmony_ci "rx_ucast_bytes", 18462306a36Sopenharmony_ci "rx_mcast_bytes", 18562306a36Sopenharmony_ci "rx_bcast_bytes", 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const char * const bnxt_ring_tx_stats_str[] = { 18962306a36Sopenharmony_ci "tx_ucast_packets", 19062306a36Sopenharmony_ci "tx_mcast_packets", 19162306a36Sopenharmony_ci "tx_bcast_packets", 19262306a36Sopenharmony_ci "tx_errors", 19362306a36Sopenharmony_ci "tx_discards", 19462306a36Sopenharmony_ci "tx_ucast_bytes", 19562306a36Sopenharmony_ci "tx_mcast_bytes", 19662306a36Sopenharmony_ci "tx_bcast_bytes", 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic const char * const bnxt_ring_tpa_stats_str[] = { 20062306a36Sopenharmony_ci "tpa_packets", 20162306a36Sopenharmony_ci "tpa_bytes", 20262306a36Sopenharmony_ci "tpa_events", 20362306a36Sopenharmony_ci "tpa_aborts", 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic const char * const bnxt_ring_tpa2_stats_str[] = { 20762306a36Sopenharmony_ci "rx_tpa_eligible_pkt", 20862306a36Sopenharmony_ci "rx_tpa_eligible_bytes", 20962306a36Sopenharmony_ci "rx_tpa_pkt", 21062306a36Sopenharmony_ci "rx_tpa_bytes", 21162306a36Sopenharmony_ci "rx_tpa_errors", 21262306a36Sopenharmony_ci "rx_tpa_events", 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic const char * const bnxt_rx_sw_stats_str[] = { 21662306a36Sopenharmony_ci "rx_l4_csum_errors", 21762306a36Sopenharmony_ci "rx_resets", 21862306a36Sopenharmony_ci "rx_buf_errors", 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const char * const bnxt_cmn_sw_stats_str[] = { 22262306a36Sopenharmony_ci "missed_irqs", 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#define BNXT_RX_STATS_ENTRY(counter) \ 22662306a36Sopenharmony_ci { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define BNXT_TX_STATS_ENTRY(counter) \ 22962306a36Sopenharmony_ci { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_ENTRY(counter) \ 23262306a36Sopenharmony_ci { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_ENTRY(counter) \ 23562306a36Sopenharmony_ci { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ 23862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ 23962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ 24262306a36Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ 24362306a36Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRIES \ 24662306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ 24762306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ 24862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ 24962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ 25062306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ 25162306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ 25262306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ 25362306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(7) 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRIES \ 25662306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ 25762306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ 25862306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ 25962306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ 26062306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ 26162306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ 26262306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ 26362306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(7) 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ 26662306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ 26762306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ 27062306a36Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ 27162306a36Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRIES \ 27462306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(0), \ 27562306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(1), \ 27662306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(2), \ 27762306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(3), \ 27862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(4), \ 27962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(5), \ 28062306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(6), \ 28162306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(7) \ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRIES \ 28462306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(0), \ 28562306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(1), \ 28662306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(2), \ 28762306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(3), \ 28862306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(4), \ 28962306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(5), \ 29062306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(6), \ 29162306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(7) \ 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ 29462306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ 29562306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ 29862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ 29962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ 30062306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ 30162306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ 30262306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ 30362306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ 30462306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ 30562306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ 30862306a36Sopenharmony_ci { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ 30962306a36Sopenharmony_ci __stringify(counter##_pri##n) } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ 31262306a36Sopenharmony_ci { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ 31362306a36Sopenharmony_ci __stringify(counter##_pri##n) } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRIES(counter) \ 31662306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ 31762306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ 31862306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ 31962306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ 32062306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ 32162306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ 32262306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ 32362306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 7) 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRIES(counter) \ 32662306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ 32762306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ 32862306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ 32962306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ 33062306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ 33162306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ 33262306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ 33362306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 7) 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cienum { 33662306a36Sopenharmony_ci RX_TOTAL_DISCARDS, 33762306a36Sopenharmony_ci TX_TOTAL_DISCARDS, 33862306a36Sopenharmony_ci RX_NETPOLL_DISCARDS, 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic const char *const bnxt_ring_err_stats_arr[] = { 34262306a36Sopenharmony_ci "rx_total_l4_csum_errors", 34362306a36Sopenharmony_ci "rx_total_resets", 34462306a36Sopenharmony_ci "rx_total_buf_errors", 34562306a36Sopenharmony_ci "rx_total_oom_discards", 34662306a36Sopenharmony_ci "rx_total_netpoll_discards", 34762306a36Sopenharmony_ci "rx_total_ring_discards", 34862306a36Sopenharmony_ci "tx_total_resets", 34962306a36Sopenharmony_ci "tx_total_ring_discards", 35062306a36Sopenharmony_ci "total_missed_irqs", 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci#define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) 35462306a36Sopenharmony_ci#define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) 35562306a36Sopenharmony_ci#define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) 35662306a36Sopenharmony_ci#define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic const struct { 35962306a36Sopenharmony_ci long offset; 36062306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 36162306a36Sopenharmony_ci} bnxt_port_stats_arr[] = { 36262306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_64b_frames), 36362306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), 36462306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), 36562306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), 36662306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), 36762306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), 36862306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), 36962306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), 37062306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), 37162306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), 37262306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), 37362306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_total_frames), 37462306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ucast_frames), 37562306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_mcast_frames), 37662306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_bcast_frames), 37762306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), 37862306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ctrl_frames), 37962306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pause_frames), 38062306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_frames), 38162306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_align_err_frames), 38262306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), 38362306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_jbr_frames), 38462306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), 38562306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_tagged_frames), 38662306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), 38762306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_good_frames), 38862306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), 38962306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), 39062306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), 39162306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), 39262306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), 39362306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), 39462306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), 39562306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), 39662306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_undrsz_frames), 39762306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), 39862306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), 39962306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_bytes), 40062306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_runt_bytes), 40162306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_runt_frames), 40262306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_stat_discard), 40362306a36Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_stat_err), 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_64b_frames), 40662306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), 40762306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), 40862306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), 40962306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), 41062306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), 41162306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), 41262306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), 41362306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), 41462306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), 41562306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), 41662306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_good_frames), 41762306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_total_frames), 41862306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_ucast_frames), 41962306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_mcast_frames), 42062306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_bcast_frames), 42162306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pause_frames), 42262306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_frames), 42362306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_jabber_frames), 42462306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), 42562306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_err), 42662306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_fifo_underruns), 42762306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), 42862306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), 42962306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), 43062306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), 43162306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), 43262306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), 43362306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), 43462306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), 43562306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), 43662306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), 43762306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_total_collisions), 43862306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_bytes), 43962306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_xthol_frames), 44062306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_stat_discard), 44162306a36Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_stat_error), 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct { 44562306a36Sopenharmony_ci long offset; 44662306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 44762306a36Sopenharmony_ci} bnxt_port_stats_ext_arr[] = { 44862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(link_down_events), 44962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), 45062306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), 45162306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), 45262306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), 45362306a36Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRIES, 45462306a36Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRIES, 45562306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_bits), 45662306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), 45762306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), 45862306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), 45962306a36Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, 46062306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), 46162306a36Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), 46262306a36Sopenharmony_ci}; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic const struct { 46562306a36Sopenharmony_ci long offset; 46662306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 46762306a36Sopenharmony_ci} bnxt_tx_port_stats_ext_arr[] = { 46862306a36Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRIES, 46962306a36Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRIES, 47062306a36Sopenharmony_ci}; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic const struct { 47362306a36Sopenharmony_ci long base_off; 47462306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 47562306a36Sopenharmony_ci} bnxt_rx_bytes_pri_arr[] = { 47662306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic const struct { 48062306a36Sopenharmony_ci long base_off; 48162306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 48262306a36Sopenharmony_ci} bnxt_rx_pkts_pri_arr[] = { 48362306a36Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRIES(rx_packets), 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic const struct { 48762306a36Sopenharmony_ci long base_off; 48862306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 48962306a36Sopenharmony_ci} bnxt_tx_bytes_pri_arr[] = { 49062306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic const struct { 49462306a36Sopenharmony_ci long base_off; 49562306a36Sopenharmony_ci char string[ETH_GSTRING_LEN]; 49662306a36Sopenharmony_ci} bnxt_tx_pkts_pri_arr[] = { 49762306a36Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRIES(tx_packets), 49862306a36Sopenharmony_ci}; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci#define BNXT_NUM_RING_ERR_STATS ARRAY_SIZE(bnxt_ring_err_stats_arr) 50162306a36Sopenharmony_ci#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) 50262306a36Sopenharmony_ci#define BNXT_NUM_STATS_PRI \ 50362306a36Sopenharmony_ci (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ 50462306a36Sopenharmony_ci ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ 50562306a36Sopenharmony_ci ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ 50662306a36Sopenharmony_ci ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci if (BNXT_SUPPORTS_TPA(bp)) { 51162306a36Sopenharmony_ci if (bp->max_tpa_v2) { 51262306a36Sopenharmony_ci if (BNXT_CHIP_P5_THOR(bp)) 51362306a36Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS_P5; 51462306a36Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS_P5_SR2; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int bnxt_get_num_ring_stats(struct bnxt *bp) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci int rx, tx, cmn; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + 52662306a36Sopenharmony_ci bnxt_get_num_tpa_ring_stats(bp); 52762306a36Sopenharmony_ci tx = NUM_RING_TX_HW_STATS; 52862306a36Sopenharmony_ci cmn = NUM_RING_CMN_SW_STATS; 52962306a36Sopenharmony_ci return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + 53062306a36Sopenharmony_ci cmn * bp->cp_nr_rings; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int bnxt_get_num_stats(struct bnxt *bp) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci int num_stats = bnxt_get_num_ring_stats(bp); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci num_stats += BNXT_NUM_RING_ERR_STATS; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) 54062306a36Sopenharmony_ci num_stats += BNXT_NUM_PORT_STATS; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 54362306a36Sopenharmony_ci num_stats += bp->fw_rx_stats_ext_size + 54462306a36Sopenharmony_ci bp->fw_tx_stats_ext_size; 54562306a36Sopenharmony_ci if (bp->pri2cos_valid) 54662306a36Sopenharmony_ci num_stats += BNXT_NUM_STATS_PRI; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return num_stats; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int bnxt_get_sset_count(struct net_device *dev, int sset) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci switch (sset) { 55762306a36Sopenharmony_ci case ETH_SS_STATS: 55862306a36Sopenharmony_ci return bnxt_get_num_stats(bp); 55962306a36Sopenharmony_ci case ETH_SS_TEST: 56062306a36Sopenharmony_ci if (!bp->num_tests) 56162306a36Sopenharmony_ci return -EOPNOTSUPP; 56262306a36Sopenharmony_ci return bp->num_tests; 56362306a36Sopenharmony_ci default: 56462306a36Sopenharmony_ci return -EOPNOTSUPP; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic bool is_rx_ring(struct bnxt *bp, int ring_num) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci return ring_num < bp->rx_nr_rings; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic bool is_tx_ring(struct bnxt *bp, int ring_num) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci int tx_base = 0; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) 57862306a36Sopenharmony_ci tx_base = bp->rx_nr_rings; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) 58162306a36Sopenharmony_ci return true; 58262306a36Sopenharmony_ci return false; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic void bnxt_get_ethtool_stats(struct net_device *dev, 58662306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct bnxt_total_ring_err_stats ring_err_stats = {0}; 58962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 59062306a36Sopenharmony_ci u64 *curr, *prev; 59162306a36Sopenharmony_ci u32 tpa_stats; 59262306a36Sopenharmony_ci u32 i, j = 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!bp->bnapi) { 59562306a36Sopenharmony_ci j += bnxt_get_num_ring_stats(bp); 59662306a36Sopenharmony_ci goto skip_ring_stats; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci tpa_stats = bnxt_get_num_tpa_ring_stats(bp); 60062306a36Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 60162306a36Sopenharmony_ci struct bnxt_napi *bnapi = bp->bnapi[i]; 60262306a36Sopenharmony_ci struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; 60362306a36Sopenharmony_ci u64 *sw_stats = cpr->stats.sw_stats; 60462306a36Sopenharmony_ci u64 *sw; 60562306a36Sopenharmony_ci int k; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (is_rx_ring(bp, i)) { 60862306a36Sopenharmony_ci for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) 60962306a36Sopenharmony_ci buf[j] = sw_stats[k]; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci if (is_tx_ring(bp, i)) { 61262306a36Sopenharmony_ci k = NUM_RING_RX_HW_STATS; 61362306a36Sopenharmony_ci for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 61462306a36Sopenharmony_ci j++, k++) 61562306a36Sopenharmony_ci buf[j] = sw_stats[k]; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci if (!tpa_stats || !is_rx_ring(bp, i)) 61862306a36Sopenharmony_ci goto skip_tpa_ring_stats; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 62162306a36Sopenharmony_ci for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + 62262306a36Sopenharmony_ci tpa_stats; j++, k++) 62362306a36Sopenharmony_ci buf[j] = sw_stats[k]; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ciskip_tpa_ring_stats: 62662306a36Sopenharmony_ci sw = (u64 *)&cpr->sw_stats.rx; 62762306a36Sopenharmony_ci if (is_rx_ring(bp, i)) { 62862306a36Sopenharmony_ci for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) 62962306a36Sopenharmony_ci buf[j] = sw[k]; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci sw = (u64 *)&cpr->sw_stats.cmn; 63362306a36Sopenharmony_ci for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) 63462306a36Sopenharmony_ci buf[j] = sw[k]; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci bnxt_get_ring_err_stats(bp, &ring_err_stats); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ciskip_ring_stats: 64062306a36Sopenharmony_ci curr = &ring_err_stats.rx_total_l4_csum_errors; 64162306a36Sopenharmony_ci prev = &bp->ring_err_stats_prev.rx_total_l4_csum_errors; 64262306a36Sopenharmony_ci for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++, j++, curr++, prev++) 64362306a36Sopenharmony_ci buf[j] = *curr + *prev; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) { 64662306a36Sopenharmony_ci u64 *port_stats = bp->port_stats.sw_stats; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) 64962306a36Sopenharmony_ci buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 65262306a36Sopenharmony_ci u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; 65362306a36Sopenharmony_ci u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { 65662306a36Sopenharmony_ci buf[j] = *(rx_port_stats_ext + 65762306a36Sopenharmony_ci bnxt_port_stats_ext_arr[i].offset); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { 66062306a36Sopenharmony_ci buf[j] = *(tx_port_stats_ext + 66162306a36Sopenharmony_ci bnxt_tx_port_stats_ext_arr[i].offset); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci if (bp->pri2cos_valid) { 66462306a36Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 66562306a36Sopenharmony_ci long n = bnxt_rx_bytes_pri_arr[i].base_off + 66662306a36Sopenharmony_ci bp->pri2cos_idx[i]; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci buf[j] = *(rx_port_stats_ext + n); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 67162306a36Sopenharmony_ci long n = bnxt_rx_pkts_pri_arr[i].base_off + 67262306a36Sopenharmony_ci bp->pri2cos_idx[i]; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci buf[j] = *(rx_port_stats_ext + n); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 67762306a36Sopenharmony_ci long n = bnxt_tx_bytes_pri_arr[i].base_off + 67862306a36Sopenharmony_ci bp->pri2cos_idx[i]; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci buf[j] = *(tx_port_stats_ext + n); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 68362306a36Sopenharmony_ci long n = bnxt_tx_pkts_pri_arr[i].base_off + 68462306a36Sopenharmony_ci bp->pri2cos_idx[i]; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci buf[j] = *(tx_port_stats_ext + n); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 69562306a36Sopenharmony_ci static const char * const *str; 69662306a36Sopenharmony_ci u32 i, j, num_str; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci switch (stringset) { 69962306a36Sopenharmony_ci case ETH_SS_STATS: 70062306a36Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 70162306a36Sopenharmony_ci if (is_rx_ring(bp, i)) { 70262306a36Sopenharmony_ci num_str = NUM_RING_RX_HW_STATS; 70362306a36Sopenharmony_ci for (j = 0; j < num_str; j++) { 70462306a36Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 70562306a36Sopenharmony_ci bnxt_ring_rx_stats_str[j]); 70662306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci if (is_tx_ring(bp, i)) { 71062306a36Sopenharmony_ci num_str = NUM_RING_TX_HW_STATS; 71162306a36Sopenharmony_ci for (j = 0; j < num_str; j++) { 71262306a36Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 71362306a36Sopenharmony_ci bnxt_ring_tx_stats_str[j]); 71462306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci num_str = bnxt_get_num_tpa_ring_stats(bp); 71862306a36Sopenharmony_ci if (!num_str || !is_rx_ring(bp, i)) 71962306a36Sopenharmony_ci goto skip_tpa_stats; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (bp->max_tpa_v2) 72262306a36Sopenharmony_ci str = bnxt_ring_tpa2_stats_str; 72362306a36Sopenharmony_ci else 72462306a36Sopenharmony_ci str = bnxt_ring_tpa_stats_str; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (j = 0; j < num_str; j++) { 72762306a36Sopenharmony_ci sprintf(buf, "[%d]: %s", i, str[j]); 72862306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ciskip_tpa_stats: 73162306a36Sopenharmony_ci if (is_rx_ring(bp, i)) { 73262306a36Sopenharmony_ci num_str = NUM_RING_RX_SW_STATS; 73362306a36Sopenharmony_ci for (j = 0; j < num_str; j++) { 73462306a36Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 73562306a36Sopenharmony_ci bnxt_rx_sw_stats_str[j]); 73662306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci num_str = NUM_RING_CMN_SW_STATS; 74062306a36Sopenharmony_ci for (j = 0; j < num_str; j++) { 74162306a36Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 74262306a36Sopenharmony_ci bnxt_cmn_sw_stats_str[j]); 74362306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) { 74762306a36Sopenharmony_ci strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN); 74862306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) { 75262306a36Sopenharmony_ci for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { 75362306a36Sopenharmony_ci strcpy(buf, bnxt_port_stats_arr[i].string); 75462306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 75862306a36Sopenharmony_ci for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { 75962306a36Sopenharmony_ci strcpy(buf, bnxt_port_stats_ext_arr[i].string); 76062306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { 76362306a36Sopenharmony_ci strcpy(buf, 76462306a36Sopenharmony_ci bnxt_tx_port_stats_ext_arr[i].string); 76562306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci if (bp->pri2cos_valid) { 76862306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 76962306a36Sopenharmony_ci strcpy(buf, 77062306a36Sopenharmony_ci bnxt_rx_bytes_pri_arr[i].string); 77162306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 77462306a36Sopenharmony_ci strcpy(buf, 77562306a36Sopenharmony_ci bnxt_rx_pkts_pri_arr[i].string); 77662306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 77962306a36Sopenharmony_ci strcpy(buf, 78062306a36Sopenharmony_ci bnxt_tx_bytes_pri_arr[i].string); 78162306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 78462306a36Sopenharmony_ci strcpy(buf, 78562306a36Sopenharmony_ci bnxt_tx_pkts_pri_arr[i].string); 78662306a36Sopenharmony_ci buf += ETH_GSTRING_LEN; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case ETH_SS_TEST: 79262306a36Sopenharmony_ci if (bp->num_tests) 79362306a36Sopenharmony_ci memcpy(buf, bp->test_info->string, 79462306a36Sopenharmony_ci bp->num_tests * ETH_GSTRING_LEN); 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", 79862306a36Sopenharmony_ci stringset); 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic void bnxt_get_ringparam(struct net_device *dev, 80462306a36Sopenharmony_ci struct ethtool_ringparam *ering, 80562306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ering, 80662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_AGG_RINGS) { 81162306a36Sopenharmony_ci ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA; 81262306a36Sopenharmony_ci ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; 81362306a36Sopenharmony_ci kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; 81462306a36Sopenharmony_ci } else { 81562306a36Sopenharmony_ci ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; 81662306a36Sopenharmony_ci ering->rx_jumbo_max_pending = 0; 81762306a36Sopenharmony_ci kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci ering->rx_pending = bp->rx_ring_size; 82262306a36Sopenharmony_ci ering->rx_jumbo_pending = bp->rx_agg_ring_size; 82362306a36Sopenharmony_ci ering->tx_pending = bp->tx_ring_size; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int bnxt_set_ringparam(struct net_device *dev, 82762306a36Sopenharmony_ci struct ethtool_ringparam *ering, 82862306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ering, 82962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || 83462306a36Sopenharmony_ci (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || 83562306a36Sopenharmony_ci (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) 83662306a36Sopenharmony_ci return -EINVAL; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (netif_running(dev)) 83962306a36Sopenharmony_ci bnxt_close_nic(bp, false, false); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci bp->rx_ring_size = ering->rx_pending; 84262306a36Sopenharmony_ci bp->tx_ring_size = ering->tx_pending; 84362306a36Sopenharmony_ci bnxt_set_ring_params(bp); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (netif_running(dev)) 84662306a36Sopenharmony_ci return bnxt_open_nic(bp, false, false); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci return 0; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void bnxt_get_channels(struct net_device *dev, 85262306a36Sopenharmony_ci struct ethtool_channels *channel) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 85562306a36Sopenharmony_ci struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 85662306a36Sopenharmony_ci int max_rx_rings, max_tx_rings, tcs; 85762306a36Sopenharmony_ci int max_tx_sch_inputs, tx_grps; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* Get the most up-to-date max_tx_sch_inputs. */ 86062306a36Sopenharmony_ci if (netif_running(dev) && BNXT_NEW_RM(bp)) 86162306a36Sopenharmony_ci bnxt_hwrm_func_resc_qcaps(bp, false); 86262306a36Sopenharmony_ci max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); 86562306a36Sopenharmony_ci if (max_tx_sch_inputs) 86662306a36Sopenharmony_ci max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci tcs = netdev_get_num_tc(dev); 86962306a36Sopenharmony_ci tx_grps = max(tcs, 1); 87062306a36Sopenharmony_ci if (bp->tx_nr_rings_xdp) 87162306a36Sopenharmony_ci tx_grps++; 87262306a36Sopenharmony_ci max_tx_rings /= tx_grps; 87362306a36Sopenharmony_ci channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { 87662306a36Sopenharmony_ci max_rx_rings = 0; 87762306a36Sopenharmony_ci max_tx_rings = 0; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci if (max_tx_sch_inputs) 88062306a36Sopenharmony_ci max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (tcs > 1) 88362306a36Sopenharmony_ci max_tx_rings /= tcs; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci channel->max_rx = max_rx_rings; 88662306a36Sopenharmony_ci channel->max_tx = max_tx_rings; 88762306a36Sopenharmony_ci channel->max_other = 0; 88862306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_SHARED_RINGS) { 88962306a36Sopenharmony_ci channel->combined_count = bp->rx_nr_rings; 89062306a36Sopenharmony_ci if (BNXT_CHIP_TYPE_NITRO_A0(bp)) 89162306a36Sopenharmony_ci channel->combined_count--; 89262306a36Sopenharmony_ci } else { 89362306a36Sopenharmony_ci if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { 89462306a36Sopenharmony_ci channel->rx_count = bp->rx_nr_rings; 89562306a36Sopenharmony_ci channel->tx_count = bp->tx_nr_rings_per_tc; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic int bnxt_set_channels(struct net_device *dev, 90162306a36Sopenharmony_ci struct ethtool_channels *channel) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 90462306a36Sopenharmony_ci int req_tx_rings, req_rx_rings, tcs; 90562306a36Sopenharmony_ci bool sh = false; 90662306a36Sopenharmony_ci int tx_xdp = 0; 90762306a36Sopenharmony_ci int rc = 0; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (channel->other_count) 91062306a36Sopenharmony_ci return -EINVAL; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!channel->combined_count && 91362306a36Sopenharmony_ci (!channel->rx_count || !channel->tx_count)) 91462306a36Sopenharmony_ci return -EINVAL; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (channel->combined_count && 91762306a36Sopenharmony_ci (channel->rx_count || channel->tx_count)) 91862306a36Sopenharmony_ci return -EINVAL; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || 92162306a36Sopenharmony_ci channel->tx_count)) 92262306a36Sopenharmony_ci return -EINVAL; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (channel->combined_count) 92562306a36Sopenharmony_ci sh = true; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci tcs = netdev_get_num_tc(dev); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci req_tx_rings = sh ? channel->combined_count : channel->tx_count; 93062306a36Sopenharmony_ci req_rx_rings = sh ? channel->combined_count : channel->rx_count; 93162306a36Sopenharmony_ci if (bp->tx_nr_rings_xdp) { 93262306a36Sopenharmony_ci if (!sh) { 93362306a36Sopenharmony_ci netdev_err(dev, "Only combined mode supported when XDP is enabled.\n"); 93462306a36Sopenharmony_ci return -EINVAL; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci tx_xdp = req_rx_rings; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); 93962306a36Sopenharmony_ci if (rc) { 94062306a36Sopenharmony_ci netdev_warn(dev, "Unable to allocate the requested rings\n"); 94162306a36Sopenharmony_ci return rc; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != 94562306a36Sopenharmony_ci bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && 94662306a36Sopenharmony_ci netif_is_rxfh_configured(dev)) { 94762306a36Sopenharmony_ci netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n"); 94862306a36Sopenharmony_ci return -EINVAL; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (netif_running(dev)) { 95262306a36Sopenharmony_ci if (BNXT_PF(bp)) { 95362306a36Sopenharmony_ci /* TODO CHIMP_FW: Send message to all VF's 95462306a36Sopenharmony_ci * before PF unload 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci bnxt_close_nic(bp, true, false); 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (sh) { 96162306a36Sopenharmony_ci bp->flags |= BNXT_FLAG_SHARED_RINGS; 96262306a36Sopenharmony_ci bp->rx_nr_rings = channel->combined_count; 96362306a36Sopenharmony_ci bp->tx_nr_rings_per_tc = channel->combined_count; 96462306a36Sopenharmony_ci } else { 96562306a36Sopenharmony_ci bp->flags &= ~BNXT_FLAG_SHARED_RINGS; 96662306a36Sopenharmony_ci bp->rx_nr_rings = channel->rx_count; 96762306a36Sopenharmony_ci bp->tx_nr_rings_per_tc = channel->tx_count; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci bp->tx_nr_rings_xdp = tx_xdp; 97062306a36Sopenharmony_ci bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; 97162306a36Sopenharmony_ci if (tcs > 1) 97262306a36Sopenharmony_ci bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : 97562306a36Sopenharmony_ci bp->tx_nr_rings + bp->rx_nr_rings; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* After changing number of rx channels, update NTUPLE feature. */ 97862306a36Sopenharmony_ci netdev_update_features(dev); 97962306a36Sopenharmony_ci if (netif_running(dev)) { 98062306a36Sopenharmony_ci rc = bnxt_open_nic(bp, true, false); 98162306a36Sopenharmony_ci if ((!rc) && BNXT_PF(bp)) { 98262306a36Sopenharmony_ci /* TODO CHIMP_FW: Send message to all VF's 98362306a36Sopenharmony_ci * to renable 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci } else { 98762306a36Sopenharmony_ci rc = bnxt_reserve_rings(bp, true); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return rc; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 99462306a36Sopenharmony_cistatic int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, 99562306a36Sopenharmony_ci u32 *rule_locs) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci int i, j = 0; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci cmd->data = bp->ntp_fltr_count; 100062306a36Sopenharmony_ci for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 100162306a36Sopenharmony_ci struct hlist_head *head; 100262306a36Sopenharmony_ci struct bnxt_ntuple_filter *fltr; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci head = &bp->ntp_fltr_hash_tbl[i]; 100562306a36Sopenharmony_ci rcu_read_lock(); 100662306a36Sopenharmony_ci hlist_for_each_entry_rcu(fltr, head, hash) { 100762306a36Sopenharmony_ci if (j == cmd->rule_cnt) 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci rule_locs[j++] = fltr->sw_id; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci rcu_read_unlock(); 101262306a36Sopenharmony_ci if (j == cmd->rule_cnt) 101362306a36Sopenharmony_ci break; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci cmd->rule_cnt = j; 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct ethtool_rx_flow_spec *fs = 102262306a36Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 102362306a36Sopenharmony_ci struct bnxt_ntuple_filter *fltr; 102462306a36Sopenharmony_ci struct flow_keys *fkeys; 102562306a36Sopenharmony_ci int i, rc = -EINVAL; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) 102862306a36Sopenharmony_ci return rc; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 103162306a36Sopenharmony_ci struct hlist_head *head; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci head = &bp->ntp_fltr_hash_tbl[i]; 103462306a36Sopenharmony_ci rcu_read_lock(); 103562306a36Sopenharmony_ci hlist_for_each_entry_rcu(fltr, head, hash) { 103662306a36Sopenharmony_ci if (fltr->sw_id == fs->location) 103762306a36Sopenharmony_ci goto fltr_found; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci rcu_read_unlock(); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci return rc; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cifltr_found: 104462306a36Sopenharmony_ci fkeys = &fltr->fkeys; 104562306a36Sopenharmony_ci if (fkeys->basic.n_proto == htons(ETH_P_IP)) { 104662306a36Sopenharmony_ci if (fkeys->basic.ip_proto == IPPROTO_TCP) 104762306a36Sopenharmony_ci fs->flow_type = TCP_V4_FLOW; 104862306a36Sopenharmony_ci else if (fkeys->basic.ip_proto == IPPROTO_UDP) 104962306a36Sopenharmony_ci fs->flow_type = UDP_V4_FLOW; 105062306a36Sopenharmony_ci else 105162306a36Sopenharmony_ci goto fltr_err; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; 105462306a36Sopenharmony_ci fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; 105762306a36Sopenharmony_ci fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; 106062306a36Sopenharmony_ci fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; 106362306a36Sopenharmony_ci fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); 106462306a36Sopenharmony_ci } else { 106562306a36Sopenharmony_ci int i; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (fkeys->basic.ip_proto == IPPROTO_TCP) 106862306a36Sopenharmony_ci fs->flow_type = TCP_V6_FLOW; 106962306a36Sopenharmony_ci else if (fkeys->basic.ip_proto == IPPROTO_UDP) 107062306a36Sopenharmony_ci fs->flow_type = UDP_V6_FLOW; 107162306a36Sopenharmony_ci else 107262306a36Sopenharmony_ci goto fltr_err; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = 107562306a36Sopenharmony_ci fkeys->addrs.v6addrs.src; 107662306a36Sopenharmony_ci *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = 107762306a36Sopenharmony_ci fkeys->addrs.v6addrs.dst; 107862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 107962306a36Sopenharmony_ci fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); 108062306a36Sopenharmony_ci fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; 108362306a36Sopenharmony_ci fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; 108662306a36Sopenharmony_ci fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci fs->ring_cookie = fltr->rxq; 109062306a36Sopenharmony_ci rc = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cifltr_err: 109362306a36Sopenharmony_ci rcu_read_unlock(); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return rc; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci#endif 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic u64 get_ethtool_ipv4_rss(struct bnxt *bp) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) 110262306a36Sopenharmony_ci return RXH_IP_SRC | RXH_IP_DST; 110362306a36Sopenharmony_ci return 0; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic u64 get_ethtool_ipv6_rss(struct bnxt *bp) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) 110962306a36Sopenharmony_ci return RXH_IP_SRC | RXH_IP_DST; 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci cmd->data = 0; 111662306a36Sopenharmony_ci switch (cmd->flow_type) { 111762306a36Sopenharmony_ci case TCP_V4_FLOW: 111862306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) 111962306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 112062306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 112162306a36Sopenharmony_ci cmd->data |= get_ethtool_ipv4_rss(bp); 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci case UDP_V4_FLOW: 112462306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) 112562306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 112662306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 112762306a36Sopenharmony_ci fallthrough; 112862306a36Sopenharmony_ci case SCTP_V4_FLOW: 112962306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 113062306a36Sopenharmony_ci case AH_V4_FLOW: 113162306a36Sopenharmony_ci case ESP_V4_FLOW: 113262306a36Sopenharmony_ci case IPV4_FLOW: 113362306a36Sopenharmony_ci cmd->data |= get_ethtool_ipv4_rss(bp); 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci case TCP_V6_FLOW: 113762306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) 113862306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 113962306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 114062306a36Sopenharmony_ci cmd->data |= get_ethtool_ipv6_rss(bp); 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case UDP_V6_FLOW: 114362306a36Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) 114462306a36Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 114562306a36Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 114662306a36Sopenharmony_ci fallthrough; 114762306a36Sopenharmony_ci case SCTP_V6_FLOW: 114862306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 114962306a36Sopenharmony_ci case AH_V6_FLOW: 115062306a36Sopenharmony_ci case ESP_V6_FLOW: 115162306a36Sopenharmony_ci case IPV6_FLOW: 115262306a36Sopenharmony_ci cmd->data |= get_ethtool_ipv6_rss(bp); 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci return 0; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 115962306a36Sopenharmony_ci#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci u32 rss_hash_cfg = bp->rss_hash_cfg; 116462306a36Sopenharmony_ci int tuple, rc = 0; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (cmd->data == RXH_4TUPLE) 116762306a36Sopenharmony_ci tuple = 4; 116862306a36Sopenharmony_ci else if (cmd->data == RXH_2TUPLE) 116962306a36Sopenharmony_ci tuple = 2; 117062306a36Sopenharmony_ci else if (!cmd->data) 117162306a36Sopenharmony_ci tuple = 0; 117262306a36Sopenharmony_ci else 117362306a36Sopenharmony_ci return -EINVAL; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (cmd->flow_type == TCP_V4_FLOW) { 117662306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 117762306a36Sopenharmony_ci if (tuple == 4) 117862306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 117962306a36Sopenharmony_ci } else if (cmd->flow_type == UDP_V4_FLOW) { 118062306a36Sopenharmony_ci if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 118162306a36Sopenharmony_ci return -EINVAL; 118262306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 118362306a36Sopenharmony_ci if (tuple == 4) 118462306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 118562306a36Sopenharmony_ci } else if (cmd->flow_type == TCP_V6_FLOW) { 118662306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 118762306a36Sopenharmony_ci if (tuple == 4) 118862306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 118962306a36Sopenharmony_ci } else if (cmd->flow_type == UDP_V6_FLOW) { 119062306a36Sopenharmony_ci if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 119162306a36Sopenharmony_ci return -EINVAL; 119262306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 119362306a36Sopenharmony_ci if (tuple == 4) 119462306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 119562306a36Sopenharmony_ci } else if (tuple == 4) { 119662306a36Sopenharmony_ci return -EINVAL; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci switch (cmd->flow_type) { 120062306a36Sopenharmony_ci case TCP_V4_FLOW: 120162306a36Sopenharmony_ci case UDP_V4_FLOW: 120262306a36Sopenharmony_ci case SCTP_V4_FLOW: 120362306a36Sopenharmony_ci case AH_ESP_V4_FLOW: 120462306a36Sopenharmony_ci case AH_V4_FLOW: 120562306a36Sopenharmony_ci case ESP_V4_FLOW: 120662306a36Sopenharmony_ci case IPV4_FLOW: 120762306a36Sopenharmony_ci if (tuple == 2) 120862306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 120962306a36Sopenharmony_ci else if (!tuple) 121062306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 121162306a36Sopenharmony_ci break; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci case TCP_V6_FLOW: 121462306a36Sopenharmony_ci case UDP_V6_FLOW: 121562306a36Sopenharmony_ci case SCTP_V6_FLOW: 121662306a36Sopenharmony_ci case AH_ESP_V6_FLOW: 121762306a36Sopenharmony_ci case AH_V6_FLOW: 121862306a36Sopenharmony_ci case ESP_V6_FLOW: 121962306a36Sopenharmony_ci case IPV6_FLOW: 122062306a36Sopenharmony_ci if (tuple == 2) 122162306a36Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 122262306a36Sopenharmony_ci else if (!tuple) 122362306a36Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 122462306a36Sopenharmony_ci break; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (bp->rss_hash_cfg == rss_hash_cfg) 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) 123162306a36Sopenharmony_ci bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg; 123262306a36Sopenharmony_ci bp->rss_hash_cfg = rss_hash_cfg; 123362306a36Sopenharmony_ci if (netif_running(bp->dev)) { 123462306a36Sopenharmony_ci bnxt_close_nic(bp, false, false); 123562306a36Sopenharmony_ci rc = bnxt_open_nic(bp, false, false); 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci return rc; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 124162306a36Sopenharmony_ci u32 *rule_locs) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 124462306a36Sopenharmony_ci int rc = 0; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci switch (cmd->cmd) { 124762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 124862306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 124962306a36Sopenharmony_ci cmd->data = bp->rx_nr_rings; 125062306a36Sopenharmony_ci break; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 125362306a36Sopenharmony_ci cmd->rule_cnt = bp->ntp_fltr_count; 125462306a36Sopenharmony_ci cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 125862306a36Sopenharmony_ci rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 126262306a36Sopenharmony_ci rc = bnxt_grxclsrule(bp, cmd); 126362306a36Sopenharmony_ci break; 126462306a36Sopenharmony_ci#endif 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci case ETHTOOL_GRXFH: 126762306a36Sopenharmony_ci rc = bnxt_grxfh(bp, cmd); 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci default: 127162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci return rc; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 128162306a36Sopenharmony_ci int rc; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci switch (cmd->cmd) { 128462306a36Sopenharmony_ci case ETHTOOL_SRXFH: 128562306a36Sopenharmony_ci rc = bnxt_srxfh(bp, cmd); 128662306a36Sopenharmony_ci break; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci default: 128962306a36Sopenharmony_ci rc = -EOPNOTSUPP; 129062306a36Sopenharmony_ci break; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci return rc; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ciu32 bnxt_get_rxfh_indir_size(struct net_device *dev) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 130062306a36Sopenharmony_ci return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 130162306a36Sopenharmony_ci return HW_HASH_INDEX_SIZE; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic u32 bnxt_get_rxfh_key_size(struct net_device *dev) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci return HW_HASH_KEY_SIZE; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 131062306a36Sopenharmony_ci u8 *hfunc) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 131362306a36Sopenharmony_ci struct bnxt_vnic_info *vnic; 131462306a36Sopenharmony_ci u32 i, tbl_size; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (hfunc) 131762306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (!bp->vnic_info) 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci vnic = &bp->vnic_info[0]; 132362306a36Sopenharmony_ci if (indir && bp->rss_indir_tbl) { 132462306a36Sopenharmony_ci tbl_size = bnxt_get_rxfh_indir_size(dev); 132562306a36Sopenharmony_ci for (i = 0; i < tbl_size; i++) 132662306a36Sopenharmony_ci indir[i] = bp->rss_indir_tbl[i]; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (key && vnic->rss_hash_key) 133062306a36Sopenharmony_ci memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci return 0; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 133662306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 133962306a36Sopenharmony_ci int rc = 0; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if (hfunc && hfunc != ETH_RSS_HASH_TOP) 134262306a36Sopenharmony_ci return -EOPNOTSUPP; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (key) 134562306a36Sopenharmony_ci return -EOPNOTSUPP; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (indir) { 134862306a36Sopenharmony_ci u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci for (i = 0; i < tbl_size; i++) 135162306a36Sopenharmony_ci bp->rss_indir_tbl[i] = indir[i]; 135262306a36Sopenharmony_ci pad = bp->rss_indir_tbl_entries - tbl_size; 135362306a36Sopenharmony_ci if (pad) 135462306a36Sopenharmony_ci memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (netif_running(bp->dev)) { 135862306a36Sopenharmony_ci bnxt_close_nic(bp, false, false); 135962306a36Sopenharmony_ci rc = bnxt_open_nic(bp, false, false); 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci return rc; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cistatic void bnxt_get_drvinfo(struct net_device *dev, 136562306a36Sopenharmony_ci struct ethtool_drvinfo *info) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 137062306a36Sopenharmony_ci strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 137162306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 137262306a36Sopenharmony_ci info->n_stats = bnxt_get_num_stats(bp); 137362306a36Sopenharmony_ci info->testinfo_len = bp->num_tests; 137462306a36Sopenharmony_ci /* TODO CHIMP_FW: eeprom dump details */ 137562306a36Sopenharmony_ci info->eedump_len = 0; 137662306a36Sopenharmony_ci /* TODO CHIMP FW: reg dump details */ 137762306a36Sopenharmony_ci info->regdump_len = 0; 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cistatic int bnxt_get_regs_len(struct net_device *dev) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 138362306a36Sopenharmony_ci int reg_len; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci if (!BNXT_PF(bp)) 138662306a36Sopenharmony_ci return -EOPNOTSUPP; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci reg_len = BNXT_PXP_REG_LEN; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 139162306a36Sopenharmony_ci reg_len += sizeof(struct pcie_ctx_hw_stats); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci return reg_len; 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 139762306a36Sopenharmony_ci void *_p) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci struct pcie_ctx_hw_stats *hw_pcie_stats; 140062306a36Sopenharmony_ci struct hwrm_pcie_qstats_input *req; 140162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 140262306a36Sopenharmony_ci dma_addr_t hw_pcie_stats_addr; 140362306a36Sopenharmony_ci int rc; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci regs->version = 0; 140662306a36Sopenharmony_ci bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 140962306a36Sopenharmony_ci return; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) 141262306a36Sopenharmony_ci return; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), 141562306a36Sopenharmony_ci &hw_pcie_stats_addr); 141662306a36Sopenharmony_ci if (!hw_pcie_stats) { 141762306a36Sopenharmony_ci hwrm_req_drop(bp, req); 141862306a36Sopenharmony_ci return; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci regs->version = 1; 142262306a36Sopenharmony_ci hwrm_req_hold(bp, req); /* hold on to slice */ 142362306a36Sopenharmony_ci req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 142462306a36Sopenharmony_ci req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 142562306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 142662306a36Sopenharmony_ci if (!rc) { 142762306a36Sopenharmony_ci __le64 *src = (__le64 *)hw_pcie_stats; 142862306a36Sopenharmony_ci u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 142962306a36Sopenharmony_ci int i; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 143262306a36Sopenharmony_ci dst[i] = le64_to_cpu(src[i]); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci hwrm_req_drop(bp, req); 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci wol->supported = 0; 144262306a36Sopenharmony_ci wol->wolopts = 0; 144362306a36Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 144462306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_WOL_CAP) { 144562306a36Sopenharmony_ci wol->supported = WAKE_MAGIC; 144662306a36Sopenharmony_ci if (bp->wol) 144762306a36Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) 145662306a36Sopenharmony_ci return -EINVAL; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 145962306a36Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 146062306a36Sopenharmony_ci return -EINVAL; 146162306a36Sopenharmony_ci if (!bp->wol) { 146262306a36Sopenharmony_ci if (bnxt_hwrm_alloc_wol_fltr(bp)) 146362306a36Sopenharmony_ci return -EBUSY; 146462306a36Sopenharmony_ci bp->wol = 1; 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci } else { 146762306a36Sopenharmony_ci if (bp->wol) { 146862306a36Sopenharmony_ci if (bnxt_hwrm_free_wol_fltr(bp)) 146962306a36Sopenharmony_ci return -EBUSY; 147062306a36Sopenharmony_ci bp->wol = 0; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ciu32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci u32 speed_mask = 0; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci /* TODO: support 25GB, 40GB, 50GB with different cable type */ 148162306a36Sopenharmony_ci /* set the advertised speeds */ 148262306a36Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 148362306a36Sopenharmony_ci speed_mask |= ADVERTISED_100baseT_Full; 148462306a36Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 148562306a36Sopenharmony_ci speed_mask |= ADVERTISED_1000baseT_Full; 148662306a36Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 148762306a36Sopenharmony_ci speed_mask |= ADVERTISED_2500baseX_Full; 148862306a36Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 148962306a36Sopenharmony_ci speed_mask |= ADVERTISED_10000baseT_Full; 149062306a36Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 149162306a36Sopenharmony_ci speed_mask |= ADVERTISED_40000baseCR4_Full; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 149462306a36Sopenharmony_ci speed_mask |= ADVERTISED_Pause; 149562306a36Sopenharmony_ci else if (fw_pause & BNXT_LINK_PAUSE_TX) 149662306a36Sopenharmony_ci speed_mask |= ADVERTISED_Asym_Pause; 149762306a36Sopenharmony_ci else if (fw_pause & BNXT_LINK_PAUSE_RX) 149862306a36Sopenharmony_ci speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci return speed_mask; 150162306a36Sopenharmony_ci} 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 150462306a36Sopenharmony_ci{ \ 150562306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 150662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150762306a36Sopenharmony_ci 100baseT_Full); \ 150862306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 150962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151062306a36Sopenharmony_ci 1000baseT_Full); \ 151162306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 151262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151362306a36Sopenharmony_ci 10000baseT_Full); \ 151462306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 151562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151662306a36Sopenharmony_ci 25000baseCR_Full); \ 151762306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 151862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151962306a36Sopenharmony_ci 40000baseCR4_Full);\ 152062306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 152162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152262306a36Sopenharmony_ci 50000baseCR2_Full);\ 152362306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 152462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152562306a36Sopenharmony_ci 100000baseCR4_Full);\ 152662306a36Sopenharmony_ci if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 152762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152862306a36Sopenharmony_ci Pause); \ 152962306a36Sopenharmony_ci if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 153062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode( \ 153162306a36Sopenharmony_ci lk_ksettings, name, Asym_Pause);\ 153262306a36Sopenharmony_ci } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 153362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153462306a36Sopenharmony_ci Asym_Pause); \ 153562306a36Sopenharmony_ci } \ 153662306a36Sopenharmony_ci} 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 153962306a36Sopenharmony_ci{ \ 154062306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154162306a36Sopenharmony_ci 100baseT_Full) || \ 154262306a36Sopenharmony_ci ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154362306a36Sopenharmony_ci 100baseT_Half)) \ 154462306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 154562306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154662306a36Sopenharmony_ci 1000baseT_Full) || \ 154762306a36Sopenharmony_ci ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154862306a36Sopenharmony_ci 1000baseT_Half)) \ 154962306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 155062306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155162306a36Sopenharmony_ci 10000baseT_Full)) \ 155262306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 155362306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155462306a36Sopenharmony_ci 25000baseCR_Full)) \ 155562306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 155662306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155762306a36Sopenharmony_ci 40000baseCR4_Full)) \ 155862306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 155962306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156062306a36Sopenharmony_ci 50000baseCR2_Full)) \ 156162306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 156262306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156362306a36Sopenharmony_ci 100000baseCR4_Full)) \ 156462306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 156562306a36Sopenharmony_ci} 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 156862306a36Sopenharmony_ci{ \ 156962306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 157062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 157162306a36Sopenharmony_ci 50000baseCR_Full); \ 157262306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 157362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 157462306a36Sopenharmony_ci 100000baseCR2_Full);\ 157562306a36Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 157662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 157762306a36Sopenharmony_ci 200000baseCR4_Full);\ 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 158162306a36Sopenharmony_ci{ \ 158262306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 158362306a36Sopenharmony_ci 50000baseCR_Full)) \ 158462306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 158562306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 158662306a36Sopenharmony_ci 100000baseCR2_Full)) \ 158762306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 158862306a36Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 158962306a36Sopenharmony_ci 200000baseCR4_Full)) \ 159062306a36Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 159462306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci u16 fec_cfg = link_info->fec_cfg; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 159962306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 160062306a36Sopenharmony_ci lk_ksettings->link_modes.advertising); 160162306a36Sopenharmony_ci return; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R) 160462306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 160562306a36Sopenharmony_ci lk_ksettings->link_modes.advertising); 160662306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS) 160762306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 160862306a36Sopenharmony_ci lk_ksettings->link_modes.advertising); 160962306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS) 161062306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 161162306a36Sopenharmony_ci lk_ksettings->link_modes.advertising); 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 161562306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci u16 fw_speeds = link_info->advertising; 161862306a36Sopenharmony_ci u8 fw_pause = 0; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 162162306a36Sopenharmony_ci fw_pause = link_info->auto_pause_setting; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 162462306a36Sopenharmony_ci fw_speeds = link_info->advertising_pam4; 162562306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 162662306a36Sopenharmony_ci bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 163062306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci u16 fw_speeds = link_info->lp_auto_link_speeds; 163362306a36Sopenharmony_ci u8 fw_pause = 0; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 163662306a36Sopenharmony_ci fw_pause = link_info->lp_pause; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 163962306a36Sopenharmony_ci lp_advertising); 164062306a36Sopenharmony_ci fw_speeds = link_info->lp_auto_pam4_link_speeds; 164162306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 164562306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci u16 fec_cfg = link_info->fec_cfg; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) { 165062306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 165162306a36Sopenharmony_ci lk_ksettings->link_modes.supported); 165262306a36Sopenharmony_ci return; 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 165562306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 165662306a36Sopenharmony_ci lk_ksettings->link_modes.supported); 165762306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 165862306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 165962306a36Sopenharmony_ci lk_ksettings->link_modes.supported); 166062306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 166162306a36Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 166262306a36Sopenharmony_ci lk_ksettings->link_modes.supported); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 166662306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 166762306a36Sopenharmony_ci{ 166862306a36Sopenharmony_ci struct bnxt *bp = container_of(link_info, struct bnxt, link_info); 166962306a36Sopenharmony_ci u16 fw_speeds = link_info->support_speeds; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 167262306a36Sopenharmony_ci fw_speeds = link_info->support_pam4_speeds; 167362306a36Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) { 167662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167762306a36Sopenharmony_ci Pause); 167862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167962306a36Sopenharmony_ci Asym_Pause); 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (link_info->support_auto_speeds || 168362306a36Sopenharmony_ci link_info->support_pam4_auto_speeds) 168462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 168562306a36Sopenharmony_ci Autoneg); 168662306a36Sopenharmony_ci bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ciu32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci switch (fw_link_speed) { 169262306a36Sopenharmony_ci case BNXT_LINK_SPEED_100MB: 169362306a36Sopenharmony_ci return SPEED_100; 169462306a36Sopenharmony_ci case BNXT_LINK_SPEED_1GB: 169562306a36Sopenharmony_ci return SPEED_1000; 169662306a36Sopenharmony_ci case BNXT_LINK_SPEED_2_5GB: 169762306a36Sopenharmony_ci return SPEED_2500; 169862306a36Sopenharmony_ci case BNXT_LINK_SPEED_10GB: 169962306a36Sopenharmony_ci return SPEED_10000; 170062306a36Sopenharmony_ci case BNXT_LINK_SPEED_20GB: 170162306a36Sopenharmony_ci return SPEED_20000; 170262306a36Sopenharmony_ci case BNXT_LINK_SPEED_25GB: 170362306a36Sopenharmony_ci return SPEED_25000; 170462306a36Sopenharmony_ci case BNXT_LINK_SPEED_40GB: 170562306a36Sopenharmony_ci return SPEED_40000; 170662306a36Sopenharmony_ci case BNXT_LINK_SPEED_50GB: 170762306a36Sopenharmony_ci return SPEED_50000; 170862306a36Sopenharmony_ci case BNXT_LINK_SPEED_100GB: 170962306a36Sopenharmony_ci return SPEED_100000; 171062306a36Sopenharmony_ci case BNXT_LINK_SPEED_200GB: 171162306a36Sopenharmony_ci return SPEED_200000; 171262306a36Sopenharmony_ci default: 171362306a36Sopenharmony_ci return SPEED_UNKNOWN; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic int bnxt_get_link_ksettings(struct net_device *dev, 171862306a36Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 172162306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 172262306a36Sopenharmony_ci struct ethtool_link_settings *base = &lk_ksettings->base; 172362306a36Sopenharmony_ci u32 ethtool_speed; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 172662306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 172762306a36Sopenharmony_ci bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 173062306a36Sopenharmony_ci if (link_info->autoneg) { 173162306a36Sopenharmony_ci bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 173262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, 173362306a36Sopenharmony_ci advertising, Autoneg); 173462306a36Sopenharmony_ci base->autoneg = AUTONEG_ENABLE; 173562306a36Sopenharmony_ci base->duplex = DUPLEX_UNKNOWN; 173662306a36Sopenharmony_ci if (link_info->phy_link_status == BNXT_LINK_LINK) { 173762306a36Sopenharmony_ci bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 173862306a36Sopenharmony_ci if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 173962306a36Sopenharmony_ci base->duplex = DUPLEX_FULL; 174062306a36Sopenharmony_ci else 174162306a36Sopenharmony_ci base->duplex = DUPLEX_HALF; 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 174462306a36Sopenharmony_ci } else { 174562306a36Sopenharmony_ci base->autoneg = AUTONEG_DISABLE; 174662306a36Sopenharmony_ci ethtool_speed = 174762306a36Sopenharmony_ci bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 174862306a36Sopenharmony_ci base->duplex = DUPLEX_HALF; 174962306a36Sopenharmony_ci if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 175062306a36Sopenharmony_ci base->duplex = DUPLEX_FULL; 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci base->speed = ethtool_speed; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci base->port = PORT_NONE; 175562306a36Sopenharmony_ci if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 175662306a36Sopenharmony_ci base->port = PORT_TP; 175762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 175862306a36Sopenharmony_ci TP); 175962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176062306a36Sopenharmony_ci TP); 176162306a36Sopenharmony_ci } else { 176262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 176362306a36Sopenharmony_ci FIBRE); 176462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176562306a36Sopenharmony_ci FIBRE); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 176862306a36Sopenharmony_ci base->port = PORT_DA; 176962306a36Sopenharmony_ci else if (link_info->media_type == 177062306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 177162306a36Sopenharmony_ci base->port = PORT_FIBRE; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci base->phy_address = link_info->phy_addr; 177462306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci return 0; 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cistatic int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 178262306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 178362306a36Sopenharmony_ci u16 support_pam4_spds = link_info->support_pam4_speeds; 178462306a36Sopenharmony_ci u16 support_spds = link_info->support_speeds; 178562306a36Sopenharmony_ci u8 sig_mode = BNXT_SIG_MODE_NRZ; 178662306a36Sopenharmony_ci u16 fw_speed = 0; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci switch (ethtool_speed) { 178962306a36Sopenharmony_ci case SPEED_100: 179062306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 179162306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci case SPEED_1000: 179462306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 179562306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci case SPEED_2500: 179862306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 179962306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 180062306a36Sopenharmony_ci break; 180162306a36Sopenharmony_ci case SPEED_10000: 180262306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 180362306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 180462306a36Sopenharmony_ci break; 180562306a36Sopenharmony_ci case SPEED_20000: 180662306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 180762306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 180862306a36Sopenharmony_ci break; 180962306a36Sopenharmony_ci case SPEED_25000: 181062306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 181162306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 181262306a36Sopenharmony_ci break; 181362306a36Sopenharmony_ci case SPEED_40000: 181462306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 181562306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 181662306a36Sopenharmony_ci break; 181762306a36Sopenharmony_ci case SPEED_50000: 181862306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 181962306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 182062306a36Sopenharmony_ci } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 182162306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 182262306a36Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci case SPEED_100000: 182662306a36Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 182762306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 182862306a36Sopenharmony_ci } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 182962306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 183062306a36Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci break; 183362306a36Sopenharmony_ci case SPEED_200000: 183462306a36Sopenharmony_ci if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 183562306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 183662306a36Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci break; 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci if (!fw_speed) { 184262306a36Sopenharmony_ci netdev_err(dev, "unsupported speed!\n"); 184362306a36Sopenharmony_ci return -EINVAL; 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (link_info->req_link_speed == fw_speed && 184762306a36Sopenharmony_ci link_info->req_signal_mode == sig_mode && 184862306a36Sopenharmony_ci link_info->autoneg == 0) 184962306a36Sopenharmony_ci return -EALREADY; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci link_info->req_link_speed = fw_speed; 185262306a36Sopenharmony_ci link_info->req_signal_mode = sig_mode; 185362306a36Sopenharmony_ci link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 185462306a36Sopenharmony_ci link_info->autoneg = 0; 185562306a36Sopenharmony_ci link_info->advertising = 0; 185662306a36Sopenharmony_ci link_info->advertising_pam4 = 0; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ciu16 bnxt_get_fw_auto_link_speeds(u32 advertising) 186262306a36Sopenharmony_ci{ 186362306a36Sopenharmony_ci u16 fw_speed_mask = 0; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* only support autoneg at speed 100, 1000, and 10000 */ 186662306a36Sopenharmony_ci if (advertising & (ADVERTISED_100baseT_Full | 186762306a36Sopenharmony_ci ADVERTISED_100baseT_Half)) { 186862306a36Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci if (advertising & (ADVERTISED_1000baseT_Full | 187162306a36Sopenharmony_ci ADVERTISED_1000baseT_Half)) { 187262306a36Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci if (advertising & ADVERTISED_10000baseT_Full) 187562306a36Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci if (advertising & ADVERTISED_40000baseCR4_Full) 187862306a36Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci return fw_speed_mask; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_cistatic int bnxt_set_link_ksettings(struct net_device *dev, 188462306a36Sopenharmony_ci const struct ethtool_link_ksettings *lk_ksettings) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 188762306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 188862306a36Sopenharmony_ci const struct ethtool_link_settings *base = &lk_ksettings->base; 188962306a36Sopenharmony_ci bool set_pause = false; 189062306a36Sopenharmony_ci u32 speed; 189162306a36Sopenharmony_ci int rc = 0; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 189462306a36Sopenharmony_ci return -EOPNOTSUPP; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 189762306a36Sopenharmony_ci if (base->autoneg == AUTONEG_ENABLE) { 189862306a36Sopenharmony_ci link_info->advertising = 0; 189962306a36Sopenharmony_ci link_info->advertising_pam4 = 0; 190062306a36Sopenharmony_ci BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 190162306a36Sopenharmony_ci advertising); 190262306a36Sopenharmony_ci BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 190362306a36Sopenharmony_ci lk_ksettings, advertising); 190462306a36Sopenharmony_ci link_info->autoneg |= BNXT_AUTONEG_SPEED; 190562306a36Sopenharmony_ci if (!link_info->advertising && !link_info->advertising_pam4) { 190662306a36Sopenharmony_ci link_info->advertising = link_info->support_auto_speeds; 190762306a36Sopenharmony_ci link_info->advertising_pam4 = 190862306a36Sopenharmony_ci link_info->support_pam4_auto_speeds; 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci /* any change to autoneg will cause link change, therefore the 191162306a36Sopenharmony_ci * driver should put back the original pause setting in autoneg 191262306a36Sopenharmony_ci */ 191362306a36Sopenharmony_ci if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 191462306a36Sopenharmony_ci set_pause = true; 191562306a36Sopenharmony_ci } else { 191662306a36Sopenharmony_ci u8 phy_type = link_info->phy_type; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 191962306a36Sopenharmony_ci phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 192062306a36Sopenharmony_ci link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 192162306a36Sopenharmony_ci netdev_err(dev, "10GBase-T devices must autoneg\n"); 192262306a36Sopenharmony_ci rc = -EINVAL; 192362306a36Sopenharmony_ci goto set_setting_exit; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci if (base->duplex == DUPLEX_HALF) { 192662306a36Sopenharmony_ci netdev_err(dev, "HALF DUPLEX is not supported!\n"); 192762306a36Sopenharmony_ci rc = -EINVAL; 192862306a36Sopenharmony_ci goto set_setting_exit; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci speed = base->speed; 193162306a36Sopenharmony_ci rc = bnxt_force_link_speed(dev, speed); 193262306a36Sopenharmony_ci if (rc) { 193362306a36Sopenharmony_ci if (rc == -EALREADY) 193462306a36Sopenharmony_ci rc = 0; 193562306a36Sopenharmony_ci goto set_setting_exit; 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci if (netif_running(dev)) 194062306a36Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ciset_setting_exit: 194362306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 194462306a36Sopenharmony_ci return rc; 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic int bnxt_get_fecparam(struct net_device *dev, 194862306a36Sopenharmony_ci struct ethtool_fecparam *fec) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 195162306a36Sopenharmony_ci struct bnxt_link_info *link_info; 195262306a36Sopenharmony_ci u8 active_fec; 195362306a36Sopenharmony_ci u16 fec_cfg; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci link_info = &bp->link_info; 195662306a36Sopenharmony_ci fec_cfg = link_info->fec_cfg; 195762306a36Sopenharmony_ci active_fec = link_info->active_fec_sig_mode & 195862306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 195962306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) { 196062306a36Sopenharmony_ci fec->fec = ETHTOOL_FEC_NONE; 196162306a36Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_NONE; 196262306a36Sopenharmony_ci return 0; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_AUTONEG) 196562306a36Sopenharmony_ci fec->fec |= ETHTOOL_FEC_AUTO; 196662306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R) 196762306a36Sopenharmony_ci fec->fec |= ETHTOOL_FEC_BASER; 196862306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS) 196962306a36Sopenharmony_ci fec->fec |= ETHTOOL_FEC_RS; 197062306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS) 197162306a36Sopenharmony_ci fec->fec |= ETHTOOL_FEC_LLRS; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci switch (active_fec) { 197462306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 197562306a36Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_BASER; 197662306a36Sopenharmony_ci break; 197762306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 197862306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 197962306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 198062306a36Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_RS; 198162306a36Sopenharmony_ci break; 198262306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 198362306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 198462306a36Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_LLRS; 198562306a36Sopenharmony_ci break; 198662306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 198762306a36Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_OFF; 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci return 0; 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic void bnxt_get_fec_stats(struct net_device *dev, 199462306a36Sopenharmony_ci struct ethtool_fec_stats *fec_stats) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 199762306a36Sopenharmony_ci u64 *rx; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 200062306a36Sopenharmony_ci return; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci rx = bp->rx_port_stats_ext.sw_stats; 200362306a36Sopenharmony_ci fec_stats->corrected_bits.total = 200462306a36Sopenharmony_ci *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (bp->fw_rx_stats_ext_size <= BNXT_RX_STATS_EXT_NUM_LEGACY) 200762306a36Sopenharmony_ci return; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci fec_stats->corrected_blocks.total = 201062306a36Sopenharmony_ci *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_corrected_blocks)); 201162306a36Sopenharmony_ci fec_stats->uncorrectable_blocks.total = 201262306a36Sopenharmony_ci *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_uncorrectable_blocks)); 201362306a36Sopenharmony_ci} 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_cistatic u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 201662306a36Sopenharmony_ci u32 fec) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if (fec & ETHTOOL_FEC_BASER) 202162306a36Sopenharmony_ci fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 202262306a36Sopenharmony_ci else if (fec & ETHTOOL_FEC_RS) 202362306a36Sopenharmony_ci fw_fec |= BNXT_FEC_RS_ON(link_info); 202462306a36Sopenharmony_ci else if (fec & ETHTOOL_FEC_LLRS) 202562306a36Sopenharmony_ci fw_fec |= BNXT_FEC_LLRS_ON; 202662306a36Sopenharmony_ci return fw_fec; 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic int bnxt_set_fecparam(struct net_device *dev, 203062306a36Sopenharmony_ci struct ethtool_fecparam *fecparam) 203162306a36Sopenharmony_ci{ 203262306a36Sopenharmony_ci struct hwrm_port_phy_cfg_input *req; 203362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 203462306a36Sopenharmony_ci struct bnxt_link_info *link_info; 203562306a36Sopenharmony_ci u32 new_cfg, fec = fecparam->fec; 203662306a36Sopenharmony_ci u16 fec_cfg; 203762306a36Sopenharmony_ci int rc; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci link_info = &bp->link_info; 204062306a36Sopenharmony_ci fec_cfg = link_info->fec_cfg; 204162306a36Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) 204262306a36Sopenharmony_ci return -EOPNOTSUPP; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci if (fec & ETHTOOL_FEC_OFF) { 204562306a36Sopenharmony_ci new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 204662306a36Sopenharmony_ci BNXT_FEC_ALL_OFF(link_info); 204762306a36Sopenharmony_ci goto apply_fec; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 205062306a36Sopenharmony_ci ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 205162306a36Sopenharmony_ci ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 205262306a36Sopenharmony_ci ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 205362306a36Sopenharmony_ci return -EINVAL; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (fec & ETHTOOL_FEC_AUTO) { 205662306a36Sopenharmony_ci if (!link_info->autoneg) 205762306a36Sopenharmony_ci return -EINVAL; 205862306a36Sopenharmony_ci new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 205962306a36Sopenharmony_ci } else { 206062306a36Sopenharmony_ci new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ciapply_fec: 206462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 206562306a36Sopenharmony_ci if (rc) 206662306a36Sopenharmony_ci return rc; 206762306a36Sopenharmony_ci req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 206862306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 206962306a36Sopenharmony_ci /* update current settings */ 207062306a36Sopenharmony_ci if (!rc) { 207162306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 207262306a36Sopenharmony_ci bnxt_update_link(bp, false); 207362306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 207462306a36Sopenharmony_ci } 207562306a36Sopenharmony_ci return rc; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic void bnxt_get_pauseparam(struct net_device *dev, 207962306a36Sopenharmony_ci struct ethtool_pauseparam *epause) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 208262306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (BNXT_VF(bp)) 208562306a36Sopenharmony_ci return; 208662306a36Sopenharmony_ci epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 208762306a36Sopenharmony_ci epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 208862306a36Sopenharmony_ci epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 208962306a36Sopenharmony_ci} 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_cistatic void bnxt_get_pause_stats(struct net_device *dev, 209262306a36Sopenharmony_ci struct ethtool_pause_stats *epstat) 209362306a36Sopenharmony_ci{ 209462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 209562306a36Sopenharmony_ci u64 *rx, *tx; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 209862306a36Sopenharmony_ci return; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci rx = bp->port_stats.sw_stats; 210162306a36Sopenharmony_ci tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 210462306a36Sopenharmony_ci epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_cistatic int bnxt_set_pauseparam(struct net_device *dev, 210862306a36Sopenharmony_ci struct ethtool_pauseparam *epause) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci int rc = 0; 211162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 211262306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 211562306a36Sopenharmony_ci return -EOPNOTSUPP; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 211862306a36Sopenharmony_ci if (epause->autoneg) { 211962306a36Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 212062306a36Sopenharmony_ci rc = -EINVAL; 212162306a36Sopenharmony_ci goto pause_exit; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 212562306a36Sopenharmony_ci link_info->req_flow_ctrl = 0; 212662306a36Sopenharmony_ci } else { 212762306a36Sopenharmony_ci /* when transition from auto pause to force pause, 212862306a36Sopenharmony_ci * force a link change 212962306a36Sopenharmony_ci */ 213062306a36Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 213162306a36Sopenharmony_ci link_info->force_link_chng = true; 213262306a36Sopenharmony_ci link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 213362306a36Sopenharmony_ci link_info->req_flow_ctrl = 0; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci if (epause->rx_pause) 213662306a36Sopenharmony_ci link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci if (epause->tx_pause) 213962306a36Sopenharmony_ci link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci if (netif_running(dev)) 214262306a36Sopenharmony_ci rc = bnxt_hwrm_set_pause(bp); 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_cipause_exit: 214562306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 214662306a36Sopenharmony_ci return rc; 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic u32 bnxt_get_link(struct net_device *dev) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci /* TODO: handle MF, VF, driver close case */ 215462306a36Sopenharmony_ci return BNXT_LINK_IS_UP(bp); 215562306a36Sopenharmony_ci} 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ciint bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 215862306a36Sopenharmony_ci struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci struct hwrm_nvm_get_dev_info_output *resp; 216162306a36Sopenharmony_ci struct hwrm_nvm_get_dev_info_input *req; 216262306a36Sopenharmony_ci int rc; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (BNXT_VF(bp)) 216562306a36Sopenharmony_ci return -EOPNOTSUPP; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 216862306a36Sopenharmony_ci if (rc) 216962306a36Sopenharmony_ci return rc; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 217262306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 217362306a36Sopenharmony_ci if (!rc) 217462306a36Sopenharmony_ci memcpy(nvm_dev_info, resp, sizeof(*resp)); 217562306a36Sopenharmony_ci hwrm_req_drop(bp, req); 217662306a36Sopenharmony_ci return rc; 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_cistatic void bnxt_print_admin_err(struct bnxt *bp) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ciint bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 218562306a36Sopenharmony_ci u16 ext, u16 *index, u32 *item_length, 218662306a36Sopenharmony_ci u32 *data_length); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ciint bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 218962306a36Sopenharmony_ci u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 219062306a36Sopenharmony_ci u32 dir_item_len, const u8 *data, 219162306a36Sopenharmony_ci size_t data_len) 219262306a36Sopenharmony_ci{ 219362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 219462306a36Sopenharmony_ci struct hwrm_nvm_write_input *req; 219562306a36Sopenharmony_ci int rc; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 219862306a36Sopenharmony_ci if (rc) 219962306a36Sopenharmony_ci return rc; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci if (data_len && data) { 220262306a36Sopenharmony_ci dma_addr_t dma_handle; 220362306a36Sopenharmony_ci u8 *kmem; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 220662306a36Sopenharmony_ci if (!kmem) { 220762306a36Sopenharmony_ci hwrm_req_drop(bp, req); 220862306a36Sopenharmony_ci return -ENOMEM; 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci req->dir_data_length = cpu_to_le32(data_len); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci memcpy(kmem, data, data_len); 221462306a36Sopenharmony_ci req->host_src_addr = cpu_to_le64(dma_handle); 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 221862306a36Sopenharmony_ci req->dir_type = cpu_to_le16(dir_type); 221962306a36Sopenharmony_ci req->dir_ordinal = cpu_to_le16(dir_ordinal); 222062306a36Sopenharmony_ci req->dir_ext = cpu_to_le16(dir_ext); 222162306a36Sopenharmony_ci req->dir_attr = cpu_to_le16(dir_attr); 222262306a36Sopenharmony_ci req->dir_item_length = cpu_to_le32(dir_item_len); 222362306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (rc == -EACCES) 222662306a36Sopenharmony_ci bnxt_print_admin_err(bp); 222762306a36Sopenharmony_ci return rc; 222862306a36Sopenharmony_ci} 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ciint bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 223162306a36Sopenharmony_ci u8 self_reset, u8 flags) 223262306a36Sopenharmony_ci{ 223362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 223462306a36Sopenharmony_ci struct hwrm_fw_reset_input *req; 223562306a36Sopenharmony_ci int rc; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci if (!bnxt_hwrm_reset_permitted(bp)) { 223862306a36Sopenharmony_ci netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 223962306a36Sopenharmony_ci return -EPERM; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 224362306a36Sopenharmony_ci if (rc) 224462306a36Sopenharmony_ci return rc; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci req->embedded_proc_type = proc_type; 224762306a36Sopenharmony_ci req->selfrst_status = self_reset; 224862306a36Sopenharmony_ci req->flags = flags; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 225162306a36Sopenharmony_ci rc = hwrm_req_send_silent(bp, req); 225262306a36Sopenharmony_ci } else { 225362306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 225462306a36Sopenharmony_ci if (rc == -EACCES) 225562306a36Sopenharmony_ci bnxt_print_admin_err(bp); 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ci return rc; 225862306a36Sopenharmony_ci} 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_cistatic int bnxt_firmware_reset(struct net_device *dev, 226162306a36Sopenharmony_ci enum bnxt_nvm_directory_type dir_type) 226262306a36Sopenharmony_ci{ 226362306a36Sopenharmony_ci u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 226462306a36Sopenharmony_ci u8 proc_type, flags = 0; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 226762306a36Sopenharmony_ci /* (e.g. when firmware isn't already running) */ 226862306a36Sopenharmony_ci switch (dir_type) { 226962306a36Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 227062306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 227162306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 227262306a36Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 227362306a36Sopenharmony_ci /* Self-reset ChiMP upon next PCIe reset: */ 227462306a36Sopenharmony_ci self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 227562306a36Sopenharmony_ci break; 227662306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 227762306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 227862306a36Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 227962306a36Sopenharmony_ci /* Self-reset APE upon next PCIe reset: */ 228062306a36Sopenharmony_ci self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 228162306a36Sopenharmony_ci break; 228262306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 228362306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 228462306a36Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 228562306a36Sopenharmony_ci break; 228662306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 228762306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 228862306a36Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 228962306a36Sopenharmony_ci break; 229062306a36Sopenharmony_ci default: 229162306a36Sopenharmony_ci return -EINVAL; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_cistatic int bnxt_firmware_reset_chip(struct net_device *dev) 229862306a36Sopenharmony_ci{ 229962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 230062306a36Sopenharmony_ci u8 flags = 0; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 230362306a36Sopenharmony_ci flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, 230662306a36Sopenharmony_ci FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 230762306a36Sopenharmony_ci FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 230862306a36Sopenharmony_ci flags); 230962306a36Sopenharmony_ci} 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_cistatic int bnxt_firmware_reset_ap(struct net_device *dev) 231262306a36Sopenharmony_ci{ 231362306a36Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 231462306a36Sopenharmony_ci FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 231562306a36Sopenharmony_ci 0); 231662306a36Sopenharmony_ci} 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_cistatic int bnxt_flash_firmware(struct net_device *dev, 231962306a36Sopenharmony_ci u16 dir_type, 232062306a36Sopenharmony_ci const u8 *fw_data, 232162306a36Sopenharmony_ci size_t fw_size) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci int rc = 0; 232462306a36Sopenharmony_ci u16 code_type; 232562306a36Sopenharmony_ci u32 stored_crc; 232662306a36Sopenharmony_ci u32 calculated_crc; 232762306a36Sopenharmony_ci struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci switch (dir_type) { 233062306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 233162306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 233262306a36Sopenharmony_ci code_type = CODE_BOOT; 233362306a36Sopenharmony_ci break; 233462306a36Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 233562306a36Sopenharmony_ci code_type = CODE_CHIMP_PATCH; 233662306a36Sopenharmony_ci break; 233762306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 233862306a36Sopenharmony_ci code_type = CODE_MCTP_PASSTHRU; 233962306a36Sopenharmony_ci break; 234062306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 234162306a36Sopenharmony_ci code_type = CODE_APE_PATCH; 234262306a36Sopenharmony_ci break; 234362306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 234462306a36Sopenharmony_ci code_type = CODE_KONG_FW; 234562306a36Sopenharmony_ci break; 234662306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 234762306a36Sopenharmony_ci code_type = CODE_KONG_PATCH; 234862306a36Sopenharmony_ci break; 234962306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 235062306a36Sopenharmony_ci code_type = CODE_BONO_FW; 235162306a36Sopenharmony_ci break; 235262306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 235362306a36Sopenharmony_ci code_type = CODE_BONO_PATCH; 235462306a36Sopenharmony_ci break; 235562306a36Sopenharmony_ci default: 235662306a36Sopenharmony_ci netdev_err(dev, "Unsupported directory entry type: %u\n", 235762306a36Sopenharmony_ci dir_type); 235862306a36Sopenharmony_ci return -EINVAL; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci if (fw_size < sizeof(struct bnxt_fw_header)) { 236162306a36Sopenharmony_ci netdev_err(dev, "Invalid firmware file size: %u\n", 236262306a36Sopenharmony_ci (unsigned int)fw_size); 236362306a36Sopenharmony_ci return -EINVAL; 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 236662306a36Sopenharmony_ci netdev_err(dev, "Invalid firmware signature: %08X\n", 236762306a36Sopenharmony_ci le32_to_cpu(header->signature)); 236862306a36Sopenharmony_ci return -EINVAL; 236962306a36Sopenharmony_ci } 237062306a36Sopenharmony_ci if (header->code_type != code_type) { 237162306a36Sopenharmony_ci netdev_err(dev, "Expected firmware type: %d, read: %d\n", 237262306a36Sopenharmony_ci code_type, header->code_type); 237362306a36Sopenharmony_ci return -EINVAL; 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci if (header->device != DEVICE_CUMULUS_FAMILY) { 237662306a36Sopenharmony_ci netdev_err(dev, "Expected firmware device family %d, read: %d\n", 237762306a36Sopenharmony_ci DEVICE_CUMULUS_FAMILY, header->device); 237862306a36Sopenharmony_ci return -EINVAL; 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci /* Confirm the CRC32 checksum of the file: */ 238162306a36Sopenharmony_ci stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 238262306a36Sopenharmony_ci sizeof(stored_crc))); 238362306a36Sopenharmony_ci calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 238462306a36Sopenharmony_ci if (calculated_crc != stored_crc) { 238562306a36Sopenharmony_ci netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 238662306a36Sopenharmony_ci (unsigned long)stored_crc, 238762306a36Sopenharmony_ci (unsigned long)calculated_crc); 238862306a36Sopenharmony_ci return -EINVAL; 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 239162306a36Sopenharmony_ci 0, 0, 0, fw_data, fw_size); 239262306a36Sopenharmony_ci if (rc == 0) /* Firmware update successful */ 239362306a36Sopenharmony_ci rc = bnxt_firmware_reset(dev, dir_type); 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci return rc; 239662306a36Sopenharmony_ci} 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_cistatic int bnxt_flash_microcode(struct net_device *dev, 239962306a36Sopenharmony_ci u16 dir_type, 240062306a36Sopenharmony_ci const u8 *fw_data, 240162306a36Sopenharmony_ci size_t fw_size) 240262306a36Sopenharmony_ci{ 240362306a36Sopenharmony_ci struct bnxt_ucode_trailer *trailer; 240462306a36Sopenharmony_ci u32 calculated_crc; 240562306a36Sopenharmony_ci u32 stored_crc; 240662306a36Sopenharmony_ci int rc = 0; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 240962306a36Sopenharmony_ci netdev_err(dev, "Invalid microcode file size: %u\n", 241062306a36Sopenharmony_ci (unsigned int)fw_size); 241162306a36Sopenharmony_ci return -EINVAL; 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 241462306a36Sopenharmony_ci sizeof(*trailer))); 241562306a36Sopenharmony_ci if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 241662306a36Sopenharmony_ci netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 241762306a36Sopenharmony_ci le32_to_cpu(trailer->sig)); 241862306a36Sopenharmony_ci return -EINVAL; 241962306a36Sopenharmony_ci } 242062306a36Sopenharmony_ci if (le16_to_cpu(trailer->dir_type) != dir_type) { 242162306a36Sopenharmony_ci netdev_err(dev, "Expected microcode type: %d, read: %d\n", 242262306a36Sopenharmony_ci dir_type, le16_to_cpu(trailer->dir_type)); 242362306a36Sopenharmony_ci return -EINVAL; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci if (le16_to_cpu(trailer->trailer_length) < 242662306a36Sopenharmony_ci sizeof(struct bnxt_ucode_trailer)) { 242762306a36Sopenharmony_ci netdev_err(dev, "Invalid microcode trailer length: %d\n", 242862306a36Sopenharmony_ci le16_to_cpu(trailer->trailer_length)); 242962306a36Sopenharmony_ci return -EINVAL; 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci /* Confirm the CRC32 checksum of the file: */ 243362306a36Sopenharmony_ci stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 243462306a36Sopenharmony_ci sizeof(stored_crc))); 243562306a36Sopenharmony_ci calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 243662306a36Sopenharmony_ci if (calculated_crc != stored_crc) { 243762306a36Sopenharmony_ci netdev_err(dev, 243862306a36Sopenharmony_ci "CRC32 (%08lX) does not match calculated: %08lX\n", 243962306a36Sopenharmony_ci (unsigned long)stored_crc, 244062306a36Sopenharmony_ci (unsigned long)calculated_crc); 244162306a36Sopenharmony_ci return -EINVAL; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 244462306a36Sopenharmony_ci 0, 0, 0, fw_data, fw_size); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci return rc; 244762306a36Sopenharmony_ci} 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cistatic bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 245062306a36Sopenharmony_ci{ 245162306a36Sopenharmony_ci switch (dir_type) { 245262306a36Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 245362306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 245462306a36Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 245562306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 245662306a36Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 245762306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 245862306a36Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 245962306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 246062306a36Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 246162306a36Sopenharmony_ci return true; 246262306a36Sopenharmony_ci } 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci return false; 246562306a36Sopenharmony_ci} 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_cistatic bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 246862306a36Sopenharmony_ci{ 246962306a36Sopenharmony_ci switch (dir_type) { 247062306a36Sopenharmony_ci case BNX_DIR_TYPE_AVS: 247162306a36Sopenharmony_ci case BNX_DIR_TYPE_EXP_ROM_MBA: 247262306a36Sopenharmony_ci case BNX_DIR_TYPE_PCIE: 247362306a36Sopenharmony_ci case BNX_DIR_TYPE_TSCF_UCODE: 247462306a36Sopenharmony_ci case BNX_DIR_TYPE_EXT_PHY: 247562306a36Sopenharmony_ci case BNX_DIR_TYPE_CCM: 247662306a36Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT: 247762306a36Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 247862306a36Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 247962306a36Sopenharmony_ci return true; 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci return false; 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_cistatic bool bnxt_dir_type_is_executable(u16 dir_type) 248662306a36Sopenharmony_ci{ 248762306a36Sopenharmony_ci return bnxt_dir_type_is_ape_bin_format(dir_type) || 248862306a36Sopenharmony_ci bnxt_dir_type_is_other_exec_format(dir_type); 248962306a36Sopenharmony_ci} 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic int bnxt_flash_firmware_from_file(struct net_device *dev, 249262306a36Sopenharmony_ci u16 dir_type, 249362306a36Sopenharmony_ci const char *filename) 249462306a36Sopenharmony_ci{ 249562306a36Sopenharmony_ci const struct firmware *fw; 249662306a36Sopenharmony_ci int rc; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci rc = request_firmware(&fw, filename, &dev->dev); 249962306a36Sopenharmony_ci if (rc != 0) { 250062306a36Sopenharmony_ci netdev_err(dev, "Error %d requesting firmware file: %s\n", 250162306a36Sopenharmony_ci rc, filename); 250262306a36Sopenharmony_ci return rc; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci if (bnxt_dir_type_is_ape_bin_format(dir_type)) 250562306a36Sopenharmony_ci rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 250662306a36Sopenharmony_ci else if (bnxt_dir_type_is_other_exec_format(dir_type)) 250762306a36Sopenharmony_ci rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 250862306a36Sopenharmony_ci else 250962306a36Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 251062306a36Sopenharmony_ci 0, 0, 0, fw->data, fw->size); 251162306a36Sopenharmony_ci release_firmware(fw); 251262306a36Sopenharmony_ci return rc; 251362306a36Sopenharmony_ci} 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci#define MSG_INTEGRITY_ERR "PKG install error : Data integrity on NVM" 251662306a36Sopenharmony_ci#define MSG_INVALID_PKG "PKG install error : Invalid package" 251762306a36Sopenharmony_ci#define MSG_AUTHENTICATION_ERR "PKG install error : Authentication error" 251862306a36Sopenharmony_ci#define MSG_INVALID_DEV "PKG install error : Invalid device" 251962306a36Sopenharmony_ci#define MSG_INTERNAL_ERR "PKG install error : Internal error" 252062306a36Sopenharmony_ci#define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" 252162306a36Sopenharmony_ci#define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" 252262306a36Sopenharmony_ci#define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" 252362306a36Sopenharmony_ci#define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" 252462306a36Sopenharmony_ci#define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_cistatic int nvm_update_err_to_stderr(struct net_device *dev, u8 result, 252762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci switch (result) { 253062306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER: 253162306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER: 253262306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR: 253362306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR: 253462306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND: 253562306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED: 253662306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_INTEGRITY_ERR); 253762306a36Sopenharmony_ci return -EINVAL; 253862306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE: 253962306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER: 254062306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE: 254162306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM: 254262306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH: 254362306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST: 254462306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER: 254562306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM: 254662306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM: 254762306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH: 254862306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE: 254962306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM: 255062306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM: 255162306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_PKG); 255262306a36Sopenharmony_ci return -ENOPKG; 255362306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR: 255462306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_AUTHENTICATION_ERR); 255562306a36Sopenharmony_ci return -EPERM; 255662306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV: 255762306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID: 255862306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR: 255962306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID: 256062306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM: 256162306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_DEV); 256262306a36Sopenharmony_ci return -EOPNOTSUPP; 256362306a36Sopenharmony_ci default: 256462306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_INTERNAL_ERR); 256562306a36Sopenharmony_ci return -EIO; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci} 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci#define BNXT_PKG_DMA_SIZE 0x40000 257062306a36Sopenharmony_ci#define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 257162306a36Sopenharmony_ci#define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, 257462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci u32 item_len; 257762306a36Sopenharmony_ci int rc; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 258062306a36Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, 258162306a36Sopenharmony_ci &item_len, NULL); 258262306a36Sopenharmony_ci if (rc) { 258362306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 258462306a36Sopenharmony_ci return rc; 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci if (fw_size > item_len) { 258862306a36Sopenharmony_ci rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE, 258962306a36Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, 0, 1, 259062306a36Sopenharmony_ci round_up(fw_size, 4096), NULL, 0); 259162306a36Sopenharmony_ci if (rc) { 259262306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); 259362306a36Sopenharmony_ci return rc; 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci return 0; 259762306a36Sopenharmony_ci} 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ciint bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 260062306a36Sopenharmony_ci u32 install_type, struct netlink_ext_ack *extack) 260162306a36Sopenharmony_ci{ 260262306a36Sopenharmony_ci struct hwrm_nvm_install_update_input *install; 260362306a36Sopenharmony_ci struct hwrm_nvm_install_update_output *resp; 260462306a36Sopenharmony_ci struct hwrm_nvm_modify_input *modify; 260562306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 260662306a36Sopenharmony_ci bool defrag_attempted = false; 260762306a36Sopenharmony_ci dma_addr_t dma_handle; 260862306a36Sopenharmony_ci u8 *kmem = NULL; 260962306a36Sopenharmony_ci u32 modify_len; 261062306a36Sopenharmony_ci u32 item_len; 261162306a36Sopenharmony_ci u8 cmd_err; 261262306a36Sopenharmony_ci u16 index; 261362306a36Sopenharmony_ci int rc; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci /* resize before flashing larger image than available space */ 261662306a36Sopenharmony_ci rc = bnxt_resize_update_entry(dev, fw->size, extack); 261762306a36Sopenharmony_ci if (rc) 261862306a36Sopenharmony_ci return rc; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci bnxt_hwrm_fw_set_time(bp); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 262362306a36Sopenharmony_ci if (rc) 262462306a36Sopenharmony_ci return rc; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci /* Try allocating a large DMA buffer first. Older fw will 262762306a36Sopenharmony_ci * cause excessive NVRAM erases when using small blocks. 262862306a36Sopenharmony_ci */ 262962306a36Sopenharmony_ci modify_len = roundup_pow_of_two(fw->size); 263062306a36Sopenharmony_ci modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 263162306a36Sopenharmony_ci while (1) { 263262306a36Sopenharmony_ci kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 263362306a36Sopenharmony_ci if (!kmem && modify_len > PAGE_SIZE) 263462306a36Sopenharmony_ci modify_len /= 2; 263562306a36Sopenharmony_ci else 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci if (!kmem) { 263962306a36Sopenharmony_ci hwrm_req_drop(bp, modify); 264062306a36Sopenharmony_ci return -ENOMEM; 264162306a36Sopenharmony_ci } 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 264462306a36Sopenharmony_ci if (rc) { 264562306a36Sopenharmony_ci hwrm_req_drop(bp, modify); 264662306a36Sopenharmony_ci return rc; 264762306a36Sopenharmony_ci } 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 265062306a36Sopenharmony_ci hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci hwrm_req_hold(bp, modify); 265362306a36Sopenharmony_ci modify->host_src_addr = cpu_to_le64(dma_handle); 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci resp = hwrm_req_hold(bp, install); 265662306a36Sopenharmony_ci if ((install_type & 0xffff) == 0) 265762306a36Sopenharmony_ci install_type >>= 16; 265862306a36Sopenharmony_ci install->install_type = cpu_to_le32(install_type); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci do { 266162306a36Sopenharmony_ci u32 copied = 0, len = modify_len; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 266462306a36Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, 266562306a36Sopenharmony_ci BNX_DIR_EXT_NONE, 266662306a36Sopenharmony_ci &index, &item_len, NULL); 266762306a36Sopenharmony_ci if (rc) { 266862306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 266962306a36Sopenharmony_ci break; 267062306a36Sopenharmony_ci } 267162306a36Sopenharmony_ci if (fw->size > item_len) { 267262306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_SPACE_ERR); 267362306a36Sopenharmony_ci rc = -EFBIG; 267462306a36Sopenharmony_ci break; 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci modify->dir_idx = cpu_to_le16(index); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci if (fw->size > modify_len) 268062306a36Sopenharmony_ci modify->flags = BNXT_NVM_MORE_FLAG; 268162306a36Sopenharmony_ci while (copied < fw->size) { 268262306a36Sopenharmony_ci u32 balance = fw->size - copied; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (balance <= modify_len) { 268562306a36Sopenharmony_ci len = balance; 268662306a36Sopenharmony_ci if (copied) 268762306a36Sopenharmony_ci modify->flags |= BNXT_NVM_LAST_FLAG; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci memcpy(kmem, fw->data + copied, len); 269062306a36Sopenharmony_ci modify->len = cpu_to_le32(len); 269162306a36Sopenharmony_ci modify->offset = cpu_to_le32(copied); 269262306a36Sopenharmony_ci rc = hwrm_req_send(bp, modify); 269362306a36Sopenharmony_ci if (rc) 269462306a36Sopenharmony_ci goto pkg_abort; 269562306a36Sopenharmony_ci copied += len; 269662306a36Sopenharmony_ci } 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci rc = hwrm_req_send_silent(bp, install); 269962306a36Sopenharmony_ci if (!rc) 270062306a36Sopenharmony_ci break; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci if (defrag_attempted) { 270362306a36Sopenharmony_ci /* We have tried to defragment already in the previous 270462306a36Sopenharmony_ci * iteration. Return with the result for INSTALL_UPDATE 270562306a36Sopenharmony_ci */ 270662306a36Sopenharmony_ci break; 270762306a36Sopenharmony_ci } 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci switch (cmd_err) { 271262306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: 271362306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_ANTI_ROLLBACK_ERR); 271462306a36Sopenharmony_ci rc = -EALREADY; 271562306a36Sopenharmony_ci break; 271662306a36Sopenharmony_ci case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: 271762306a36Sopenharmony_ci install->flags = 271862306a36Sopenharmony_ci cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci rc = hwrm_req_send_silent(bp, install); 272162306a36Sopenharmony_ci if (!rc) 272262306a36Sopenharmony_ci break; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 272762306a36Sopenharmony_ci /* FW has cleared NVM area, driver will create 272862306a36Sopenharmony_ci * UPDATE directory and try the flash again 272962306a36Sopenharmony_ci */ 273062306a36Sopenharmony_ci defrag_attempted = true; 273162306a36Sopenharmony_ci install->flags = 0; 273262306a36Sopenharmony_ci rc = bnxt_flash_nvram(bp->dev, 273362306a36Sopenharmony_ci BNX_DIR_TYPE_UPDATE, 273462306a36Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, 273562306a36Sopenharmony_ci 0, 0, item_len, NULL, 0); 273662306a36Sopenharmony_ci if (!rc) 273762306a36Sopenharmony_ci break; 273862306a36Sopenharmony_ci } 273962306a36Sopenharmony_ci fallthrough; 274062306a36Sopenharmony_ci default: 274162306a36Sopenharmony_ci BNXT_NVM_ERR_MSG(dev, extack, MSG_GENERIC_FAILURE_ERR); 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci } while (defrag_attempted && !rc); 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_cipkg_abort: 274662306a36Sopenharmony_ci hwrm_req_drop(bp, modify); 274762306a36Sopenharmony_ci hwrm_req_drop(bp, install); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci if (resp->result) { 275062306a36Sopenharmony_ci netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 275162306a36Sopenharmony_ci (s8)resp->result, (int)resp->problem_item); 275262306a36Sopenharmony_ci rc = nvm_update_err_to_stderr(dev, resp->result, extack); 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci if (rc == -EACCES) 275562306a36Sopenharmony_ci bnxt_print_admin_err(bp); 275662306a36Sopenharmony_ci return rc; 275762306a36Sopenharmony_ci} 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_cistatic int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 276062306a36Sopenharmony_ci u32 install_type, struct netlink_ext_ack *extack) 276162306a36Sopenharmony_ci{ 276262306a36Sopenharmony_ci const struct firmware *fw; 276362306a36Sopenharmony_ci int rc; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci rc = request_firmware(&fw, filename, &dev->dev); 276662306a36Sopenharmony_ci if (rc != 0) { 276762306a36Sopenharmony_ci netdev_err(dev, "PKG error %d requesting file: %s\n", 276862306a36Sopenharmony_ci rc, filename); 276962306a36Sopenharmony_ci return rc; 277062306a36Sopenharmony_ci } 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type, extack); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci release_firmware(fw); 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci return rc; 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_cistatic int bnxt_flash_device(struct net_device *dev, 278062306a36Sopenharmony_ci struct ethtool_flash *flash) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 278362306a36Sopenharmony_ci netdev_err(dev, "flashdev not supported from a virtual function\n"); 278462306a36Sopenharmony_ci return -EINVAL; 278562306a36Sopenharmony_ci } 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 278862306a36Sopenharmony_ci flash->region > 0xffff) 278962306a36Sopenharmony_ci return bnxt_flash_package_from_file(dev, flash->data, 279062306a36Sopenharmony_ci flash->region, NULL); 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 279362306a36Sopenharmony_ci} 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_cistatic int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 279662306a36Sopenharmony_ci{ 279762306a36Sopenharmony_ci struct hwrm_nvm_get_dir_info_output *output; 279862306a36Sopenharmony_ci struct hwrm_nvm_get_dir_info_input *req; 279962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 280062306a36Sopenharmony_ci int rc; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 280362306a36Sopenharmony_ci if (rc) 280462306a36Sopenharmony_ci return rc; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci output = hwrm_req_hold(bp, req); 280762306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 280862306a36Sopenharmony_ci if (!rc) { 280962306a36Sopenharmony_ci *entries = le32_to_cpu(output->entries); 281062306a36Sopenharmony_ci *length = le32_to_cpu(output->entry_length); 281162306a36Sopenharmony_ci } 281262306a36Sopenharmony_ci hwrm_req_drop(bp, req); 281362306a36Sopenharmony_ci return rc; 281462306a36Sopenharmony_ci} 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_cistatic int bnxt_get_eeprom_len(struct net_device *dev) 281762306a36Sopenharmony_ci{ 281862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci if (BNXT_VF(bp)) 282162306a36Sopenharmony_ci return 0; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci /* The -1 return value allows the entire 32-bit range of offsets to be 282462306a36Sopenharmony_ci * passed via the ethtool command-line utility. 282562306a36Sopenharmony_ci */ 282662306a36Sopenharmony_ci return -1; 282762306a36Sopenharmony_ci} 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_cistatic int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 283062306a36Sopenharmony_ci{ 283162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 283262306a36Sopenharmony_ci int rc; 283362306a36Sopenharmony_ci u32 dir_entries; 283462306a36Sopenharmony_ci u32 entry_length; 283562306a36Sopenharmony_ci u8 *buf; 283662306a36Sopenharmony_ci size_t buflen; 283762306a36Sopenharmony_ci dma_addr_t dma_handle; 283862306a36Sopenharmony_ci struct hwrm_nvm_get_dir_entries_input *req; 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 284162306a36Sopenharmony_ci if (rc != 0) 284262306a36Sopenharmony_ci return rc; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci if (!dir_entries || !entry_length) 284562306a36Sopenharmony_ci return -EIO; 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci /* Insert 2 bytes of directory info (count and size of entries) */ 284862306a36Sopenharmony_ci if (len < 2) 284962306a36Sopenharmony_ci return -EINVAL; 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci *data++ = dir_entries; 285262306a36Sopenharmony_ci *data++ = entry_length; 285362306a36Sopenharmony_ci len -= 2; 285462306a36Sopenharmony_ci memset(data, 0xff, len); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 285762306a36Sopenharmony_ci if (rc) 285862306a36Sopenharmony_ci return rc; 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci buflen = mul_u32_u32(dir_entries, entry_length); 286162306a36Sopenharmony_ci buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 286262306a36Sopenharmony_ci if (!buf) { 286362306a36Sopenharmony_ci hwrm_req_drop(bp, req); 286462306a36Sopenharmony_ci return -ENOMEM; 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci req->host_dest_addr = cpu_to_le64(dma_handle); 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci hwrm_req_hold(bp, req); /* hold the slice */ 286962306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 287062306a36Sopenharmony_ci if (rc == 0) 287162306a36Sopenharmony_ci memcpy(data, buf, len > buflen ? buflen : len); 287262306a36Sopenharmony_ci hwrm_req_drop(bp, req); 287362306a36Sopenharmony_ci return rc; 287462306a36Sopenharmony_ci} 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ciint bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 287762306a36Sopenharmony_ci u32 length, u8 *data) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 288062306a36Sopenharmony_ci int rc; 288162306a36Sopenharmony_ci u8 *buf; 288262306a36Sopenharmony_ci dma_addr_t dma_handle; 288362306a36Sopenharmony_ci struct hwrm_nvm_read_input *req; 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci if (!length) 288662306a36Sopenharmony_ci return -EINVAL; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 288962306a36Sopenharmony_ci if (rc) 289062306a36Sopenharmony_ci return rc; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 289362306a36Sopenharmony_ci if (!buf) { 289462306a36Sopenharmony_ci hwrm_req_drop(bp, req); 289562306a36Sopenharmony_ci return -ENOMEM; 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci req->host_dest_addr = cpu_to_le64(dma_handle); 289962306a36Sopenharmony_ci req->dir_idx = cpu_to_le16(index); 290062306a36Sopenharmony_ci req->offset = cpu_to_le32(offset); 290162306a36Sopenharmony_ci req->len = cpu_to_le32(length); 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci hwrm_req_hold(bp, req); /* hold the slice */ 290462306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 290562306a36Sopenharmony_ci if (rc == 0) 290662306a36Sopenharmony_ci memcpy(data, buf, length); 290762306a36Sopenharmony_ci hwrm_req_drop(bp, req); 290862306a36Sopenharmony_ci return rc; 290962306a36Sopenharmony_ci} 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ciint bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 291262306a36Sopenharmony_ci u16 ext, u16 *index, u32 *item_length, 291362306a36Sopenharmony_ci u32 *data_length) 291462306a36Sopenharmony_ci{ 291562306a36Sopenharmony_ci struct hwrm_nvm_find_dir_entry_output *output; 291662306a36Sopenharmony_ci struct hwrm_nvm_find_dir_entry_input *req; 291762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 291862306a36Sopenharmony_ci int rc; 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 292162306a36Sopenharmony_ci if (rc) 292262306a36Sopenharmony_ci return rc; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci req->enables = 0; 292562306a36Sopenharmony_ci req->dir_idx = 0; 292662306a36Sopenharmony_ci req->dir_type = cpu_to_le16(type); 292762306a36Sopenharmony_ci req->dir_ordinal = cpu_to_le16(ordinal); 292862306a36Sopenharmony_ci req->dir_ext = cpu_to_le16(ext); 292962306a36Sopenharmony_ci req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 293062306a36Sopenharmony_ci output = hwrm_req_hold(bp, req); 293162306a36Sopenharmony_ci rc = hwrm_req_send_silent(bp, req); 293262306a36Sopenharmony_ci if (rc == 0) { 293362306a36Sopenharmony_ci if (index) 293462306a36Sopenharmony_ci *index = le16_to_cpu(output->dir_idx); 293562306a36Sopenharmony_ci if (item_length) 293662306a36Sopenharmony_ci *item_length = le32_to_cpu(output->dir_item_length); 293762306a36Sopenharmony_ci if (data_length) 293862306a36Sopenharmony_ci *data_length = le32_to_cpu(output->dir_data_length); 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci hwrm_req_drop(bp, req); 294162306a36Sopenharmony_ci return rc; 294262306a36Sopenharmony_ci} 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_cistatic char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 294562306a36Sopenharmony_ci{ 294662306a36Sopenharmony_ci char *retval = NULL; 294762306a36Sopenharmony_ci char *p; 294862306a36Sopenharmony_ci char *value; 294962306a36Sopenharmony_ci int field = 0; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci if (datalen < 1) 295262306a36Sopenharmony_ci return NULL; 295362306a36Sopenharmony_ci /* null-terminate the log data (removing last '\n'): */ 295462306a36Sopenharmony_ci data[datalen - 1] = 0; 295562306a36Sopenharmony_ci for (p = data; *p != 0; p++) { 295662306a36Sopenharmony_ci field = 0; 295762306a36Sopenharmony_ci retval = NULL; 295862306a36Sopenharmony_ci while (*p != 0 && *p != '\n') { 295962306a36Sopenharmony_ci value = p; 296062306a36Sopenharmony_ci while (*p != 0 && *p != '\t' && *p != '\n') 296162306a36Sopenharmony_ci p++; 296262306a36Sopenharmony_ci if (field == desired_field) 296362306a36Sopenharmony_ci retval = value; 296462306a36Sopenharmony_ci if (*p != '\t') 296562306a36Sopenharmony_ci break; 296662306a36Sopenharmony_ci *p = 0; 296762306a36Sopenharmony_ci field++; 296862306a36Sopenharmony_ci p++; 296962306a36Sopenharmony_ci } 297062306a36Sopenharmony_ci if (*p == 0) 297162306a36Sopenharmony_ci break; 297262306a36Sopenharmony_ci *p = 0; 297362306a36Sopenharmony_ci } 297462306a36Sopenharmony_ci return retval; 297562306a36Sopenharmony_ci} 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ciint bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 297862306a36Sopenharmony_ci{ 297962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 298062306a36Sopenharmony_ci u16 index = 0; 298162306a36Sopenharmony_ci char *pkgver; 298262306a36Sopenharmony_ci u32 pkglen; 298362306a36Sopenharmony_ci u8 *pkgbuf; 298462306a36Sopenharmony_ci int rc; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 298762306a36Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 298862306a36Sopenharmony_ci &index, NULL, &pkglen); 298962306a36Sopenharmony_ci if (rc) 299062306a36Sopenharmony_ci return rc; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci pkgbuf = kzalloc(pkglen, GFP_KERNEL); 299362306a36Sopenharmony_ci if (!pkgbuf) { 299462306a36Sopenharmony_ci dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 299562306a36Sopenharmony_ci pkglen); 299662306a36Sopenharmony_ci return -ENOMEM; 299762306a36Sopenharmony_ci } 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 300062306a36Sopenharmony_ci if (rc) 300162306a36Sopenharmony_ci goto err; 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 300462306a36Sopenharmony_ci pkglen); 300562306a36Sopenharmony_ci if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 300662306a36Sopenharmony_ci strscpy(ver, pkgver, size); 300762306a36Sopenharmony_ci else 300862306a36Sopenharmony_ci rc = -ENOENT; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_cierr: 301162306a36Sopenharmony_ci kfree(pkgbuf); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci return rc; 301462306a36Sopenharmony_ci} 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_cistatic void bnxt_get_pkgver(struct net_device *dev) 301762306a36Sopenharmony_ci{ 301862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 301962306a36Sopenharmony_ci char buf[FW_VER_STR_LEN]; 302062306a36Sopenharmony_ci int len; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 302362306a36Sopenharmony_ci len = strlen(bp->fw_ver_str); 302462306a36Sopenharmony_ci snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 302562306a36Sopenharmony_ci "/pkg %s", buf); 302662306a36Sopenharmony_ci } 302762306a36Sopenharmony_ci} 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_cistatic int bnxt_get_eeprom(struct net_device *dev, 303062306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, 303162306a36Sopenharmony_ci u8 *data) 303262306a36Sopenharmony_ci{ 303362306a36Sopenharmony_ci u32 index; 303462306a36Sopenharmony_ci u32 offset; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci if (eeprom->offset == 0) /* special offset value to get directory */ 303762306a36Sopenharmony_ci return bnxt_get_nvram_directory(dev, eeprom->len, data); 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci index = eeprom->offset >> 24; 304062306a36Sopenharmony_ci offset = eeprom->offset & 0xffffff; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci if (index == 0) { 304362306a36Sopenharmony_ci netdev_err(dev, "unsupported index value: %d\n", index); 304462306a36Sopenharmony_ci return -EINVAL; 304562306a36Sopenharmony_ci } 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 304862306a36Sopenharmony_ci} 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_cistatic int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 305162306a36Sopenharmony_ci{ 305262306a36Sopenharmony_ci struct hwrm_nvm_erase_dir_entry_input *req; 305362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 305462306a36Sopenharmony_ci int rc; 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 305762306a36Sopenharmony_ci if (rc) 305862306a36Sopenharmony_ci return rc; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci req->dir_idx = cpu_to_le16(index); 306162306a36Sopenharmony_ci return hwrm_req_send(bp, req); 306262306a36Sopenharmony_ci} 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_cistatic int bnxt_set_eeprom(struct net_device *dev, 306562306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, 306662306a36Sopenharmony_ci u8 *data) 306762306a36Sopenharmony_ci{ 306862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 306962306a36Sopenharmony_ci u8 index, dir_op; 307062306a36Sopenharmony_ci u16 type, ext, ordinal, attr; 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci if (!BNXT_PF(bp)) { 307362306a36Sopenharmony_ci netdev_err(dev, "NVM write not supported from a virtual function\n"); 307462306a36Sopenharmony_ci return -EINVAL; 307562306a36Sopenharmony_ci } 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci type = eeprom->magic >> 16; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci if (type == 0xffff) { /* special value for directory operations */ 308062306a36Sopenharmony_ci index = eeprom->magic & 0xff; 308162306a36Sopenharmony_ci dir_op = eeprom->magic >> 8; 308262306a36Sopenharmony_ci if (index == 0) 308362306a36Sopenharmony_ci return -EINVAL; 308462306a36Sopenharmony_ci switch (dir_op) { 308562306a36Sopenharmony_ci case 0x0e: /* erase */ 308662306a36Sopenharmony_ci if (eeprom->offset != ~eeprom->magic) 308762306a36Sopenharmony_ci return -EINVAL; 308862306a36Sopenharmony_ci return bnxt_erase_nvram_directory(dev, index - 1); 308962306a36Sopenharmony_ci default: 309062306a36Sopenharmony_ci return -EINVAL; 309162306a36Sopenharmony_ci } 309262306a36Sopenharmony_ci } 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci /* Create or re-write an NVM item: */ 309562306a36Sopenharmony_ci if (bnxt_dir_type_is_executable(type)) 309662306a36Sopenharmony_ci return -EOPNOTSUPP; 309762306a36Sopenharmony_ci ext = eeprom->magic & 0xffff; 309862306a36Sopenharmony_ci ordinal = eeprom->offset >> 16; 309962306a36Sopenharmony_ci attr = eeprom->offset & 0xffff; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 310262306a36Sopenharmony_ci eeprom->len); 310362306a36Sopenharmony_ci} 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_cistatic int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 310662306a36Sopenharmony_ci{ 310762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 310862306a36Sopenharmony_ci struct ethtool_eee *eee = &bp->eee; 310962306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 311062306a36Sopenharmony_ci u32 advertising; 311162306a36Sopenharmony_ci int rc = 0; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 311462306a36Sopenharmony_ci return -EOPNOTSUPP; 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 311762306a36Sopenharmony_ci return -EOPNOTSUPP; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci mutex_lock(&bp->link_lock); 312062306a36Sopenharmony_ci advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 312162306a36Sopenharmony_ci if (!edata->eee_enabled) 312262306a36Sopenharmony_ci goto eee_ok; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 312562306a36Sopenharmony_ci netdev_warn(dev, "EEE requires autoneg\n"); 312662306a36Sopenharmony_ci rc = -EINVAL; 312762306a36Sopenharmony_ci goto eee_exit; 312862306a36Sopenharmony_ci } 312962306a36Sopenharmony_ci if (edata->tx_lpi_enabled) { 313062306a36Sopenharmony_ci if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 313162306a36Sopenharmony_ci edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 313262306a36Sopenharmony_ci netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 313362306a36Sopenharmony_ci bp->lpi_tmr_lo, bp->lpi_tmr_hi); 313462306a36Sopenharmony_ci rc = -EINVAL; 313562306a36Sopenharmony_ci goto eee_exit; 313662306a36Sopenharmony_ci } else if (!bp->lpi_tmr_hi) { 313762306a36Sopenharmony_ci edata->tx_lpi_timer = eee->tx_lpi_timer; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci } 314062306a36Sopenharmony_ci if (!edata->advertised) { 314162306a36Sopenharmony_ci edata->advertised = advertising & eee->supported; 314262306a36Sopenharmony_ci } else if (edata->advertised & ~advertising) { 314362306a36Sopenharmony_ci netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 314462306a36Sopenharmony_ci edata->advertised, advertising); 314562306a36Sopenharmony_ci rc = -EINVAL; 314662306a36Sopenharmony_ci goto eee_exit; 314762306a36Sopenharmony_ci } 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci eee->advertised = edata->advertised; 315062306a36Sopenharmony_ci eee->tx_lpi_enabled = edata->tx_lpi_enabled; 315162306a36Sopenharmony_ci eee->tx_lpi_timer = edata->tx_lpi_timer; 315262306a36Sopenharmony_cieee_ok: 315362306a36Sopenharmony_ci eee->eee_enabled = edata->eee_enabled; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci if (netif_running(dev)) 315662306a36Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, false, true); 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_cieee_exit: 315962306a36Sopenharmony_ci mutex_unlock(&bp->link_lock); 316062306a36Sopenharmony_ci return rc; 316162306a36Sopenharmony_ci} 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_cistatic int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 316462306a36Sopenharmony_ci{ 316562306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 316862306a36Sopenharmony_ci return -EOPNOTSUPP; 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci *edata = bp->eee; 317162306a36Sopenharmony_ci if (!bp->eee.eee_enabled) { 317262306a36Sopenharmony_ci /* Preserve tx_lpi_timer so that the last value will be used 317362306a36Sopenharmony_ci * by default when it is re-enabled. 317462306a36Sopenharmony_ci */ 317562306a36Sopenharmony_ci edata->advertised = 0; 317662306a36Sopenharmony_ci edata->tx_lpi_enabled = 0; 317762306a36Sopenharmony_ci } 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci if (!bp->eee.eee_active) 318062306a36Sopenharmony_ci edata->lp_advertised = 0; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci return 0; 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_cistatic int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 318662306a36Sopenharmony_ci u16 page_number, u8 bank, 318762306a36Sopenharmony_ci u16 start_addr, u16 data_length, 318862306a36Sopenharmony_ci u8 *buf) 318962306a36Sopenharmony_ci{ 319062306a36Sopenharmony_ci struct hwrm_port_phy_i2c_read_output *output; 319162306a36Sopenharmony_ci struct hwrm_port_phy_i2c_read_input *req; 319262306a36Sopenharmony_ci int rc, byte_offset = 0; 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 319562306a36Sopenharmony_ci if (rc) 319662306a36Sopenharmony_ci return rc; 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci output = hwrm_req_hold(bp, req); 319962306a36Sopenharmony_ci req->i2c_slave_addr = i2c_addr; 320062306a36Sopenharmony_ci req->page_number = cpu_to_le16(page_number); 320162306a36Sopenharmony_ci req->port_id = cpu_to_le16(bp->pf.port_id); 320262306a36Sopenharmony_ci do { 320362306a36Sopenharmony_ci u16 xfer_size; 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 320662306a36Sopenharmony_ci data_length -= xfer_size; 320762306a36Sopenharmony_ci req->page_offset = cpu_to_le16(start_addr + byte_offset); 320862306a36Sopenharmony_ci req->data_length = xfer_size; 320962306a36Sopenharmony_ci req->enables = 321062306a36Sopenharmony_ci cpu_to_le32((start_addr + byte_offset ? 321162306a36Sopenharmony_ci PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 321262306a36Sopenharmony_ci 0) | 321362306a36Sopenharmony_ci (bank ? 321462306a36Sopenharmony_ci PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : 321562306a36Sopenharmony_ci 0)); 321662306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 321762306a36Sopenharmony_ci if (!rc) 321862306a36Sopenharmony_ci memcpy(buf + byte_offset, output->data, xfer_size); 321962306a36Sopenharmony_ci byte_offset += xfer_size; 322062306a36Sopenharmony_ci } while (!rc && data_length > 0); 322162306a36Sopenharmony_ci hwrm_req_drop(bp, req); 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci return rc; 322462306a36Sopenharmony_ci} 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_cistatic int bnxt_get_module_info(struct net_device *dev, 322762306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 323062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 323162306a36Sopenharmony_ci int rc; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci /* No point in going further if phy status indicates 323462306a36Sopenharmony_ci * module is not inserted or if it is powered down or 323562306a36Sopenharmony_ci * if it is of type 10GBase-T 323662306a36Sopenharmony_ci */ 323762306a36Sopenharmony_ci if (bp->link_info.module_status > 323862306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 323962306a36Sopenharmony_ci return -EOPNOTSUPP; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci /* This feature is not supported in older firmware versions */ 324262306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10202) 324362306a36Sopenharmony_ci return -EOPNOTSUPP; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, 324662306a36Sopenharmony_ci SFF_DIAG_SUPPORT_OFFSET + 1, 324762306a36Sopenharmony_ci data); 324862306a36Sopenharmony_ci if (!rc) { 324962306a36Sopenharmony_ci u8 module_id = data[0]; 325062306a36Sopenharmony_ci u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci switch (module_id) { 325362306a36Sopenharmony_ci case SFF_MODULE_ID_SFP: 325462306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 325562306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 325662306a36Sopenharmony_ci if (!diag_supported) 325762306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 325862306a36Sopenharmony_ci break; 325962306a36Sopenharmony_ci case SFF_MODULE_ID_QSFP: 326062306a36Sopenharmony_ci case SFF_MODULE_ID_QSFP_PLUS: 326162306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 326262306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 326362306a36Sopenharmony_ci break; 326462306a36Sopenharmony_ci case SFF_MODULE_ID_QSFP28: 326562306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 326662306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 326762306a36Sopenharmony_ci break; 326862306a36Sopenharmony_ci default: 326962306a36Sopenharmony_ci rc = -EOPNOTSUPP; 327062306a36Sopenharmony_ci break; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci } 327362306a36Sopenharmony_ci return rc; 327462306a36Sopenharmony_ci} 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_cistatic int bnxt_get_module_eeprom(struct net_device *dev, 327762306a36Sopenharmony_ci struct ethtool_eeprom *eeprom, 327862306a36Sopenharmony_ci u8 *data) 327962306a36Sopenharmony_ci{ 328062306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 328162306a36Sopenharmony_ci u16 start = eeprom->offset, length = eeprom->len; 328262306a36Sopenharmony_ci int rc = 0; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci memset(data, 0, eeprom->len); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci /* Read A0 portion of the EEPROM */ 328762306a36Sopenharmony_ci if (start < ETH_MODULE_SFF_8436_LEN) { 328862306a36Sopenharmony_ci if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 328962306a36Sopenharmony_ci length = ETH_MODULE_SFF_8436_LEN - start; 329062306a36Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 329162306a36Sopenharmony_ci start, length, data); 329262306a36Sopenharmony_ci if (rc) 329362306a36Sopenharmony_ci return rc; 329462306a36Sopenharmony_ci start += length; 329562306a36Sopenharmony_ci data += length; 329662306a36Sopenharmony_ci length = eeprom->len - length; 329762306a36Sopenharmony_ci } 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci /* Read A2 portion of the EEPROM */ 330062306a36Sopenharmony_ci if (length) { 330162306a36Sopenharmony_ci start -= ETH_MODULE_SFF_8436_LEN; 330262306a36Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, 330362306a36Sopenharmony_ci start, length, data); 330462306a36Sopenharmony_ci } 330562306a36Sopenharmony_ci return rc; 330662306a36Sopenharmony_ci} 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_cistatic int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) 330962306a36Sopenharmony_ci{ 331062306a36Sopenharmony_ci if (bp->link_info.module_status <= 331162306a36Sopenharmony_ci PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 331262306a36Sopenharmony_ci return 0; 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci switch (bp->link_info.module_status) { 331562306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: 331662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); 331762306a36Sopenharmony_ci break; 331862306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: 331962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); 332062306a36Sopenharmony_ci break; 332162306a36Sopenharmony_ci case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: 332262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault"); 332362306a36Sopenharmony_ci break; 332462306a36Sopenharmony_ci default: 332562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown error"); 332662306a36Sopenharmony_ci break; 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci return -EINVAL; 332962306a36Sopenharmony_ci} 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_cistatic int bnxt_get_module_eeprom_by_page(struct net_device *dev, 333262306a36Sopenharmony_ci const struct ethtool_module_eeprom *page_data, 333362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 333462306a36Sopenharmony_ci{ 333562306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 333662306a36Sopenharmony_ci int rc; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci rc = bnxt_get_module_status(bp, extack); 333962306a36Sopenharmony_ci if (rc) 334062306a36Sopenharmony_ci return rc; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10202) { 334362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); 334462306a36Sopenharmony_ci return -EINVAL; 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { 334862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); 334962306a36Sopenharmony_ci return -EINVAL; 335062306a36Sopenharmony_ci } 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, 335362306a36Sopenharmony_ci page_data->page, page_data->bank, 335462306a36Sopenharmony_ci page_data->offset, 335562306a36Sopenharmony_ci page_data->length, 335662306a36Sopenharmony_ci page_data->data); 335762306a36Sopenharmony_ci if (rc) { 335862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); 335962306a36Sopenharmony_ci return rc; 336062306a36Sopenharmony_ci } 336162306a36Sopenharmony_ci return page_data->length; 336262306a36Sopenharmony_ci} 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_cistatic int bnxt_nway_reset(struct net_device *dev) 336562306a36Sopenharmony_ci{ 336662306a36Sopenharmony_ci int rc = 0; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 336962306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 337262306a36Sopenharmony_ci return -EOPNOTSUPP; 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 337562306a36Sopenharmony_ci return -EINVAL; 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci if (netif_running(dev)) 337862306a36Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, true, false); 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci return rc; 338162306a36Sopenharmony_ci} 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_cistatic int bnxt_set_phys_id(struct net_device *dev, 338462306a36Sopenharmony_ci enum ethtool_phys_id_state state) 338562306a36Sopenharmony_ci{ 338662306a36Sopenharmony_ci struct hwrm_port_led_cfg_input *req; 338762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 338862306a36Sopenharmony_ci struct bnxt_pf_info *pf = &bp->pf; 338962306a36Sopenharmony_ci struct bnxt_led_cfg *led_cfg; 339062306a36Sopenharmony_ci u8 led_state; 339162306a36Sopenharmony_ci __le16 duration; 339262306a36Sopenharmony_ci int rc, i; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci if (!bp->num_leds || BNXT_VF(bp)) 339562306a36Sopenharmony_ci return -EOPNOTSUPP; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci if (state == ETHTOOL_ID_ACTIVE) { 339862306a36Sopenharmony_ci led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 339962306a36Sopenharmony_ci duration = cpu_to_le16(500); 340062306a36Sopenharmony_ci } else if (state == ETHTOOL_ID_INACTIVE) { 340162306a36Sopenharmony_ci led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 340262306a36Sopenharmony_ci duration = cpu_to_le16(0); 340362306a36Sopenharmony_ci } else { 340462306a36Sopenharmony_ci return -EINVAL; 340562306a36Sopenharmony_ci } 340662306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 340762306a36Sopenharmony_ci if (rc) 340862306a36Sopenharmony_ci return rc; 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci req->port_id = cpu_to_le16(pf->port_id); 341162306a36Sopenharmony_ci req->num_leds = bp->num_leds; 341262306a36Sopenharmony_ci led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 341362306a36Sopenharmony_ci for (i = 0; i < bp->num_leds; i++, led_cfg++) { 341462306a36Sopenharmony_ci req->enables |= BNXT_LED_DFLT_ENABLES(i); 341562306a36Sopenharmony_ci led_cfg->led_id = bp->leds[i].led_id; 341662306a36Sopenharmony_ci led_cfg->led_state = led_state; 341762306a36Sopenharmony_ci led_cfg->led_blink_on = duration; 341862306a36Sopenharmony_ci led_cfg->led_blink_off = duration; 341962306a36Sopenharmony_ci led_cfg->led_group_id = bp->leds[i].led_group_id; 342062306a36Sopenharmony_ci } 342162306a36Sopenharmony_ci return hwrm_req_send(bp, req); 342262306a36Sopenharmony_ci} 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_cistatic int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 342562306a36Sopenharmony_ci{ 342662306a36Sopenharmony_ci struct hwrm_selftest_irq_input *req; 342762306a36Sopenharmony_ci int rc; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 343062306a36Sopenharmony_ci if (rc) 343162306a36Sopenharmony_ci return rc; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci req->cmpl_ring = cpu_to_le16(cmpl_ring); 343462306a36Sopenharmony_ci return hwrm_req_send(bp, req); 343562306a36Sopenharmony_ci} 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_cistatic int bnxt_test_irq(struct bnxt *bp) 343862306a36Sopenharmony_ci{ 343962306a36Sopenharmony_ci int i; 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 344262306a36Sopenharmony_ci u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 344362306a36Sopenharmony_ci int rc; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 344662306a36Sopenharmony_ci if (rc) 344762306a36Sopenharmony_ci return rc; 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci return 0; 345062306a36Sopenharmony_ci} 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_cistatic int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 345362306a36Sopenharmony_ci{ 345462306a36Sopenharmony_ci struct hwrm_port_mac_cfg_input *req; 345562306a36Sopenharmony_ci int rc; 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 345862306a36Sopenharmony_ci if (rc) 345962306a36Sopenharmony_ci return rc; 346062306a36Sopenharmony_ci 346162306a36Sopenharmony_ci req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 346262306a36Sopenharmony_ci if (enable) 346362306a36Sopenharmony_ci req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 346462306a36Sopenharmony_ci else 346562306a36Sopenharmony_ci req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 346662306a36Sopenharmony_ci return hwrm_req_send(bp, req); 346762306a36Sopenharmony_ci} 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_cistatic int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 347062306a36Sopenharmony_ci{ 347162306a36Sopenharmony_ci struct hwrm_port_phy_qcaps_output *resp; 347262306a36Sopenharmony_ci struct hwrm_port_phy_qcaps_input *req; 347362306a36Sopenharmony_ci int rc; 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 347662306a36Sopenharmony_ci if (rc) 347762306a36Sopenharmony_ci return rc; 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 348062306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 348162306a36Sopenharmony_ci if (!rc) 348262306a36Sopenharmony_ci *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci hwrm_req_drop(bp, req); 348562306a36Sopenharmony_ci return rc; 348662306a36Sopenharmony_ci} 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_cistatic int bnxt_disable_an_for_lpbk(struct bnxt *bp, 348962306a36Sopenharmony_ci struct hwrm_port_phy_cfg_input *req) 349062306a36Sopenharmony_ci{ 349162306a36Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 349262306a36Sopenharmony_ci u16 fw_advertising; 349362306a36Sopenharmony_ci u16 fw_speed; 349462306a36Sopenharmony_ci int rc; 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci if (!link_info->autoneg || 349762306a36Sopenharmony_ci (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 349862306a36Sopenharmony_ci return 0; 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci rc = bnxt_query_force_speeds(bp, &fw_advertising); 350162306a36Sopenharmony_ci if (rc) 350262306a36Sopenharmony_ci return rc; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 350562306a36Sopenharmony_ci if (BNXT_LINK_IS_UP(bp)) 350662306a36Sopenharmony_ci fw_speed = bp->link_info.link_speed; 350762306a36Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 350862306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 350962306a36Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 351062306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 351162306a36Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 351262306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 351362306a36Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 351462306a36Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci req->force_link_speed = cpu_to_le16(fw_speed); 351762306a36Sopenharmony_ci req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 351862306a36Sopenharmony_ci PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 351962306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 352062306a36Sopenharmony_ci req->flags = 0; 352162306a36Sopenharmony_ci req->force_link_speed = cpu_to_le16(0); 352262306a36Sopenharmony_ci return rc; 352362306a36Sopenharmony_ci} 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_cistatic int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 352662306a36Sopenharmony_ci{ 352762306a36Sopenharmony_ci struct hwrm_port_phy_cfg_input *req; 352862306a36Sopenharmony_ci int rc; 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 353162306a36Sopenharmony_ci if (rc) 353262306a36Sopenharmony_ci return rc; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 353562306a36Sopenharmony_ci hwrm_req_hold(bp, req); 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci if (enable) { 353862306a36Sopenharmony_ci bnxt_disable_an_for_lpbk(bp, req); 353962306a36Sopenharmony_ci if (ext) 354062306a36Sopenharmony_ci req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 354162306a36Sopenharmony_ci else 354262306a36Sopenharmony_ci req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 354362306a36Sopenharmony_ci } else { 354462306a36Sopenharmony_ci req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 354562306a36Sopenharmony_ci } 354662306a36Sopenharmony_ci req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 354762306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 354862306a36Sopenharmony_ci hwrm_req_drop(bp, req); 354962306a36Sopenharmony_ci return rc; 355062306a36Sopenharmony_ci} 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_cistatic int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 355362306a36Sopenharmony_ci u32 raw_cons, int pkt_size) 355462306a36Sopenharmony_ci{ 355562306a36Sopenharmony_ci struct bnxt_napi *bnapi = cpr->bnapi; 355662306a36Sopenharmony_ci struct bnxt_rx_ring_info *rxr; 355762306a36Sopenharmony_ci struct bnxt_sw_rx_bd *rx_buf; 355862306a36Sopenharmony_ci struct rx_cmp *rxcmp; 355962306a36Sopenharmony_ci u16 cp_cons, cons; 356062306a36Sopenharmony_ci u8 *data; 356162306a36Sopenharmony_ci u32 len; 356262306a36Sopenharmony_ci int i; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci rxr = bnapi->rx_ring; 356562306a36Sopenharmony_ci cp_cons = RING_CMP(raw_cons); 356662306a36Sopenharmony_ci rxcmp = (struct rx_cmp *) 356762306a36Sopenharmony_ci &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 356862306a36Sopenharmony_ci cons = rxcmp->rx_cmp_opaque; 356962306a36Sopenharmony_ci rx_buf = &rxr->rx_buf_ring[cons]; 357062306a36Sopenharmony_ci data = rx_buf->data_ptr; 357162306a36Sopenharmony_ci len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 357262306a36Sopenharmony_ci if (len != pkt_size) 357362306a36Sopenharmony_ci return -EIO; 357462306a36Sopenharmony_ci i = ETH_ALEN; 357562306a36Sopenharmony_ci if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 357662306a36Sopenharmony_ci return -EIO; 357762306a36Sopenharmony_ci i += ETH_ALEN; 357862306a36Sopenharmony_ci for ( ; i < pkt_size; i++) { 357962306a36Sopenharmony_ci if (data[i] != (u8)(i & 0xff)) 358062306a36Sopenharmony_ci return -EIO; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci return 0; 358362306a36Sopenharmony_ci} 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_cistatic int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 358662306a36Sopenharmony_ci int pkt_size) 358762306a36Sopenharmony_ci{ 358862306a36Sopenharmony_ci struct tx_cmp *txcmp; 358962306a36Sopenharmony_ci int rc = -EIO; 359062306a36Sopenharmony_ci u32 raw_cons; 359162306a36Sopenharmony_ci u32 cons; 359262306a36Sopenharmony_ci int i; 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci raw_cons = cpr->cp_raw_cons; 359562306a36Sopenharmony_ci for (i = 0; i < 200; i++) { 359662306a36Sopenharmony_ci cons = RING_CMP(raw_cons); 359762306a36Sopenharmony_ci txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci if (!TX_CMP_VALID(txcmp, raw_cons)) { 360062306a36Sopenharmony_ci udelay(5); 360162306a36Sopenharmony_ci continue; 360262306a36Sopenharmony_ci } 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci /* The valid test of the entry must be done first before 360562306a36Sopenharmony_ci * reading any further. 360662306a36Sopenharmony_ci */ 360762306a36Sopenharmony_ci dma_rmb(); 360862306a36Sopenharmony_ci if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 360962306a36Sopenharmony_ci rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 361062306a36Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 361162306a36Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 361262306a36Sopenharmony_ci break; 361362306a36Sopenharmony_ci } 361462306a36Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 361562306a36Sopenharmony_ci } 361662306a36Sopenharmony_ci cpr->cp_raw_cons = raw_cons; 361762306a36Sopenharmony_ci return rc; 361862306a36Sopenharmony_ci} 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_cistatic int bnxt_run_loopback(struct bnxt *bp) 362162306a36Sopenharmony_ci{ 362262306a36Sopenharmony_ci struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 362362306a36Sopenharmony_ci struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 362462306a36Sopenharmony_ci struct bnxt_cp_ring_info *cpr; 362562306a36Sopenharmony_ci int pkt_size, i = 0; 362662306a36Sopenharmony_ci struct sk_buff *skb; 362762306a36Sopenharmony_ci dma_addr_t map; 362862306a36Sopenharmony_ci u8 *data; 362962306a36Sopenharmony_ci int rc; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci cpr = &rxr->bnapi->cp_ring; 363262306a36Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 363362306a36Sopenharmony_ci cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 363462306a36Sopenharmony_ci pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 363562306a36Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, pkt_size); 363662306a36Sopenharmony_ci if (!skb) 363762306a36Sopenharmony_ci return -ENOMEM; 363862306a36Sopenharmony_ci data = skb_put(skb, pkt_size); 363962306a36Sopenharmony_ci ether_addr_copy(&data[i], bp->dev->dev_addr); 364062306a36Sopenharmony_ci i += ETH_ALEN; 364162306a36Sopenharmony_ci ether_addr_copy(&data[i], bp->dev->dev_addr); 364262306a36Sopenharmony_ci i += ETH_ALEN; 364362306a36Sopenharmony_ci for ( ; i < pkt_size; i++) 364462306a36Sopenharmony_ci data[i] = (u8)(i & 0xff); 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 364762306a36Sopenharmony_ci DMA_TO_DEVICE); 364862306a36Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, map)) { 364962306a36Sopenharmony_ci dev_kfree_skb(skb); 365062306a36Sopenharmony_ci return -EIO; 365162306a36Sopenharmony_ci } 365262306a36Sopenharmony_ci bnxt_xmit_bd(bp, txr, map, pkt_size, NULL); 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci /* Sync BD data before updating doorbell */ 365562306a36Sopenharmony_ci wmb(); 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 365862306a36Sopenharmony_ci rc = bnxt_poll_loopback(bp, cpr, pkt_size); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 366162306a36Sopenharmony_ci dev_kfree_skb(skb); 366262306a36Sopenharmony_ci return rc; 366362306a36Sopenharmony_ci} 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_cistatic int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 366662306a36Sopenharmony_ci{ 366762306a36Sopenharmony_ci struct hwrm_selftest_exec_output *resp; 366862306a36Sopenharmony_ci struct hwrm_selftest_exec_input *req; 366962306a36Sopenharmony_ci int rc; 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 367262306a36Sopenharmony_ci if (rc) 367362306a36Sopenharmony_ci return rc; 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci hwrm_req_timeout(bp, req, bp->test_info->timeout); 367662306a36Sopenharmony_ci req->flags = test_mask; 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 367962306a36Sopenharmony_ci rc = hwrm_req_send(bp, req); 368062306a36Sopenharmony_ci *test_results = resp->test_success; 368162306a36Sopenharmony_ci hwrm_req_drop(bp, req); 368262306a36Sopenharmony_ci return rc; 368362306a36Sopenharmony_ci} 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ci#define BNXT_DRV_TESTS 4 368662306a36Sopenharmony_ci#define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 368762306a36Sopenharmony_ci#define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 368862306a36Sopenharmony_ci#define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 368962306a36Sopenharmony_ci#define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_cistatic void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 369262306a36Sopenharmony_ci u64 *buf) 369362306a36Sopenharmony_ci{ 369462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 369562306a36Sopenharmony_ci bool do_ext_lpbk = false; 369662306a36Sopenharmony_ci bool offline = false; 369762306a36Sopenharmony_ci u8 test_results = 0; 369862306a36Sopenharmony_ci u8 test_mask = 0; 369962306a36Sopenharmony_ci int rc = 0, i; 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci if (!bp->num_tests || !BNXT_PF(bp)) 370262306a36Sopenharmony_ci return; 370362306a36Sopenharmony_ci memset(buf, 0, sizeof(u64) * bp->num_tests); 370462306a36Sopenharmony_ci if (!netif_running(dev)) { 370562306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 370662306a36Sopenharmony_ci return; 370762306a36Sopenharmony_ci } 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 371062306a36Sopenharmony_ci (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 371162306a36Sopenharmony_ci do_ext_lpbk = true; 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_ci if (etest->flags & ETH_TEST_FL_OFFLINE) { 371462306a36Sopenharmony_ci if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 371562306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 371662306a36Sopenharmony_ci netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 371762306a36Sopenharmony_ci return; 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_ci offline = true; 372062306a36Sopenharmony_ci } 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 372362306a36Sopenharmony_ci u8 bit_val = 1 << i; 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_ci if (!(bp->test_info->offline_mask & bit_val)) 372662306a36Sopenharmony_ci test_mask |= bit_val; 372762306a36Sopenharmony_ci else if (offline) 372862306a36Sopenharmony_ci test_mask |= bit_val; 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci if (!offline) { 373162306a36Sopenharmony_ci bnxt_run_fw_tests(bp, test_mask, &test_results); 373262306a36Sopenharmony_ci } else { 373362306a36Sopenharmony_ci bnxt_ulp_stop(bp); 373462306a36Sopenharmony_ci bnxt_close_nic(bp, true, false); 373562306a36Sopenharmony_ci bnxt_run_fw_tests(bp, test_mask, &test_results); 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci buf[BNXT_MACLPBK_TEST_IDX] = 1; 373862306a36Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, true); 373962306a36Sopenharmony_ci msleep(250); 374062306a36Sopenharmony_ci rc = bnxt_half_open_nic(bp); 374162306a36Sopenharmony_ci if (rc) { 374262306a36Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, false); 374362306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 374462306a36Sopenharmony_ci bnxt_ulp_start(bp, rc); 374562306a36Sopenharmony_ci return; 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci if (bnxt_run_loopback(bp)) 374862306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 374962306a36Sopenharmony_ci else 375062306a36Sopenharmony_ci buf[BNXT_MACLPBK_TEST_IDX] = 0; 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, false); 375362306a36Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, true, false); 375462306a36Sopenharmony_ci msleep(1000); 375562306a36Sopenharmony_ci if (bnxt_run_loopback(bp)) { 375662306a36Sopenharmony_ci buf[BNXT_PHYLPBK_TEST_IDX] = 1; 375762306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 375862306a36Sopenharmony_ci } 375962306a36Sopenharmony_ci if (do_ext_lpbk) { 376062306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 376162306a36Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, true, true); 376262306a36Sopenharmony_ci msleep(1000); 376362306a36Sopenharmony_ci if (bnxt_run_loopback(bp)) { 376462306a36Sopenharmony_ci buf[BNXT_EXTLPBK_TEST_IDX] = 1; 376562306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 376662306a36Sopenharmony_ci } 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, false, false); 376962306a36Sopenharmony_ci bnxt_half_close_nic(bp); 377062306a36Sopenharmony_ci rc = bnxt_open_nic(bp, true, true); 377162306a36Sopenharmony_ci bnxt_ulp_start(bp, rc); 377262306a36Sopenharmony_ci } 377362306a36Sopenharmony_ci if (rc || bnxt_test_irq(bp)) { 377462306a36Sopenharmony_ci buf[BNXT_IRQ_TEST_IDX] = 1; 377562306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 377662306a36Sopenharmony_ci } 377762306a36Sopenharmony_ci for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 377862306a36Sopenharmony_ci u8 bit_val = 1 << i; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci if ((test_mask & bit_val) && !(test_results & bit_val)) { 378162306a36Sopenharmony_ci buf[i] = 1; 378262306a36Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 378362306a36Sopenharmony_ci } 378462306a36Sopenharmony_ci } 378562306a36Sopenharmony_ci} 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_cistatic int bnxt_reset(struct net_device *dev, u32 *flags) 378862306a36Sopenharmony_ci{ 378962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 379062306a36Sopenharmony_ci bool reload = false; 379162306a36Sopenharmony_ci u32 req = *flags; 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci if (!req) 379462306a36Sopenharmony_ci return -EINVAL; 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_ci if (!BNXT_PF(bp)) { 379762306a36Sopenharmony_ci netdev_err(dev, "Reset is not supported from a VF\n"); 379862306a36Sopenharmony_ci return -EOPNOTSUPP; 379962306a36Sopenharmony_ci } 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci if (pci_vfs_assigned(bp->pdev) && 380262306a36Sopenharmony_ci !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 380362306a36Sopenharmony_ci netdev_err(dev, 380462306a36Sopenharmony_ci "Reset not allowed when VFs are assigned to VMs\n"); 380562306a36Sopenharmony_ci return -EBUSY; 380662306a36Sopenharmony_ci } 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 380962306a36Sopenharmony_ci /* This feature is not supported in older firmware versions */ 381062306a36Sopenharmony_ci if (bp->hwrm_spec_code >= 0x10803) { 381162306a36Sopenharmony_ci if (!bnxt_firmware_reset_chip(dev)) { 381262306a36Sopenharmony_ci netdev_info(dev, "Firmware reset request successful.\n"); 381362306a36Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 381462306a36Sopenharmony_ci reload = true; 381562306a36Sopenharmony_ci *flags &= ~BNXT_FW_RESET_CHIP; 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci } else if (req == BNXT_FW_RESET_CHIP) { 381862306a36Sopenharmony_ci return -EOPNOTSUPP; /* only request, fail hard */ 381962306a36Sopenharmony_ci } 382062306a36Sopenharmony_ci } 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) { 382362306a36Sopenharmony_ci /* This feature is not supported in older firmware versions */ 382462306a36Sopenharmony_ci if (bp->hwrm_spec_code >= 0x10803) { 382562306a36Sopenharmony_ci if (!bnxt_firmware_reset_ap(dev)) { 382662306a36Sopenharmony_ci netdev_info(dev, "Reset application processor successful.\n"); 382762306a36Sopenharmony_ci reload = true; 382862306a36Sopenharmony_ci *flags &= ~BNXT_FW_RESET_AP; 382962306a36Sopenharmony_ci } 383062306a36Sopenharmony_ci } else if (req == BNXT_FW_RESET_AP) { 383162306a36Sopenharmony_ci return -EOPNOTSUPP; /* only request, fail hard */ 383262306a36Sopenharmony_ci } 383362306a36Sopenharmony_ci } 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci if (reload) 383662306a36Sopenharmony_ci netdev_info(dev, "Reload driver to complete reset\n"); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci return 0; 383962306a36Sopenharmony_ci} 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_cistatic int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 384262306a36Sopenharmony_ci{ 384362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci if (dump->flag > BNXT_DUMP_CRASH) { 384662306a36Sopenharmony_ci netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 384762306a36Sopenharmony_ci return -EINVAL; 384862306a36Sopenharmony_ci } 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 385162306a36Sopenharmony_ci netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 385262306a36Sopenharmony_ci return -EOPNOTSUPP; 385362306a36Sopenharmony_ci } 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci bp->dump_flag = dump->flag; 385662306a36Sopenharmony_ci return 0; 385762306a36Sopenharmony_ci} 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_cistatic int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 386062306a36Sopenharmony_ci{ 386162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10801) 386462306a36Sopenharmony_ci return -EOPNOTSUPP; 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ci dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 386762306a36Sopenharmony_ci bp->ver_resp.hwrm_fw_min_8b << 16 | 386862306a36Sopenharmony_ci bp->ver_resp.hwrm_fw_bld_8b << 8 | 386962306a36Sopenharmony_ci bp->ver_resp.hwrm_fw_rsvd_8b; 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci dump->flag = bp->dump_flag; 387262306a36Sopenharmony_ci dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 387362306a36Sopenharmony_ci return 0; 387462306a36Sopenharmony_ci} 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_cistatic int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 387762306a36Sopenharmony_ci void *buf) 387862306a36Sopenharmony_ci{ 387962306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10801) 388262306a36Sopenharmony_ci return -EOPNOTSUPP; 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci memset(buf, 0, dump->len); 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci dump->flag = bp->dump_flag; 388762306a36Sopenharmony_ci return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 388862306a36Sopenharmony_ci} 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_cistatic int bnxt_get_ts_info(struct net_device *dev, 389162306a36Sopenharmony_ci struct ethtool_ts_info *info) 389262306a36Sopenharmony_ci{ 389362306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 389462306a36Sopenharmony_ci struct bnxt_ptp_cfg *ptp; 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci ptp = bp->ptp_cfg; 389762306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 389862306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 389962306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci info->phc_index = -1; 390262306a36Sopenharmony_ci if (!ptp) 390362306a36Sopenharmony_ci return 0; 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 390662306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 390762306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 390862306a36Sopenharmony_ci if (ptp->ptp_clock) 390962306a36Sopenharmony_ci info->phc_index = ptp_clock_index(ptp->ptp_clock); 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 391462306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 391562306a36Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) 391862306a36Sopenharmony_ci info->rx_filters |= (1 << HWTSTAMP_FILTER_ALL); 391962306a36Sopenharmony_ci return 0; 392062306a36Sopenharmony_ci} 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_civoid bnxt_ethtool_init(struct bnxt *bp) 392362306a36Sopenharmony_ci{ 392462306a36Sopenharmony_ci struct hwrm_selftest_qlist_output *resp; 392562306a36Sopenharmony_ci struct hwrm_selftest_qlist_input *req; 392662306a36Sopenharmony_ci struct bnxt_test_info *test_info; 392762306a36Sopenharmony_ci struct net_device *dev = bp->dev; 392862306a36Sopenharmony_ci int i, rc; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 393162306a36Sopenharmony_ci bnxt_get_pkgver(dev); 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci bp->num_tests = 0; 393462306a36Sopenharmony_ci if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 393562306a36Sopenharmony_ci return; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci test_info = bp->test_info; 393862306a36Sopenharmony_ci if (!test_info) { 393962306a36Sopenharmony_ci test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 394062306a36Sopenharmony_ci if (!test_info) 394162306a36Sopenharmony_ci return; 394262306a36Sopenharmony_ci bp->test_info = test_info; 394362306a36Sopenharmony_ci } 394462306a36Sopenharmony_ci 394562306a36Sopenharmony_ci if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 394662306a36Sopenharmony_ci return; 394762306a36Sopenharmony_ci 394862306a36Sopenharmony_ci resp = hwrm_req_hold(bp, req); 394962306a36Sopenharmony_ci rc = hwrm_req_send_silent(bp, req); 395062306a36Sopenharmony_ci if (rc) 395162306a36Sopenharmony_ci goto ethtool_init_exit; 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 395462306a36Sopenharmony_ci if (bp->num_tests > BNXT_MAX_TEST) 395562306a36Sopenharmony_ci bp->num_tests = BNXT_MAX_TEST; 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci test_info->offline_mask = resp->offline_tests; 395862306a36Sopenharmony_ci test_info->timeout = le16_to_cpu(resp->test_timeout); 395962306a36Sopenharmony_ci if (!test_info->timeout) 396062306a36Sopenharmony_ci test_info->timeout = HWRM_CMD_TIMEOUT; 396162306a36Sopenharmony_ci for (i = 0; i < bp->num_tests; i++) { 396262306a36Sopenharmony_ci char *str = test_info->string[i]; 396362306a36Sopenharmony_ci char *fw_str = resp->test_name[i]; 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci if (i == BNXT_MACLPBK_TEST_IDX) { 396662306a36Sopenharmony_ci strcpy(str, "Mac loopback test (offline)"); 396762306a36Sopenharmony_ci } else if (i == BNXT_PHYLPBK_TEST_IDX) { 396862306a36Sopenharmony_ci strcpy(str, "Phy loopback test (offline)"); 396962306a36Sopenharmony_ci } else if (i == BNXT_EXTLPBK_TEST_IDX) { 397062306a36Sopenharmony_ci strcpy(str, "Ext loopback test (offline)"); 397162306a36Sopenharmony_ci } else if (i == BNXT_IRQ_TEST_IDX) { 397262306a36Sopenharmony_ci strcpy(str, "Interrupt_test (offline)"); 397362306a36Sopenharmony_ci } else { 397462306a36Sopenharmony_ci snprintf(str, ETH_GSTRING_LEN, "%s test (%s)", 397562306a36Sopenharmony_ci fw_str, test_info->offline_mask & (1 << i) ? 397662306a36Sopenharmony_ci "offline" : "online"); 397762306a36Sopenharmony_ci } 397862306a36Sopenharmony_ci } 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ciethtool_init_exit: 398162306a36Sopenharmony_ci hwrm_req_drop(bp, req); 398262306a36Sopenharmony_ci} 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_cistatic void bnxt_get_eth_phy_stats(struct net_device *dev, 398562306a36Sopenharmony_ci struct ethtool_eth_phy_stats *phy_stats) 398662306a36Sopenharmony_ci{ 398762306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 398862306a36Sopenharmony_ci u64 *rx; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 399162306a36Sopenharmony_ci return; 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci rx = bp->rx_port_stats_ext.sw_stats; 399462306a36Sopenharmony_ci phy_stats->SymbolErrorDuringCarrier = 399562306a36Sopenharmony_ci *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 399662306a36Sopenharmony_ci} 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_cistatic void bnxt_get_eth_mac_stats(struct net_device *dev, 399962306a36Sopenharmony_ci struct ethtool_eth_mac_stats *mac_stats) 400062306a36Sopenharmony_ci{ 400162306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 400262306a36Sopenharmony_ci u64 *rx, *tx; 400362306a36Sopenharmony_ci 400462306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 400562306a36Sopenharmony_ci return; 400662306a36Sopenharmony_ci 400762306a36Sopenharmony_ci rx = bp->port_stats.sw_stats; 400862306a36Sopenharmony_ci tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci mac_stats->FramesReceivedOK = 401162306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 401262306a36Sopenharmony_ci mac_stats->FramesTransmittedOK = 401362306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 401462306a36Sopenharmony_ci mac_stats->FrameCheckSequenceErrors = 401562306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 401662306a36Sopenharmony_ci mac_stats->AlignmentErrors = 401762306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 401862306a36Sopenharmony_ci mac_stats->OutOfRangeLengthField = 401962306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 402062306a36Sopenharmony_ci} 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_cistatic void bnxt_get_eth_ctrl_stats(struct net_device *dev, 402362306a36Sopenharmony_ci struct ethtool_eth_ctrl_stats *ctrl_stats) 402462306a36Sopenharmony_ci{ 402562306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 402662306a36Sopenharmony_ci u64 *rx; 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 402962306a36Sopenharmony_ci return; 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_ci rx = bp->port_stats.sw_stats; 403262306a36Sopenharmony_ci ctrl_stats->MACControlFramesReceived = 403362306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 403462306a36Sopenharmony_ci} 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_cistatic const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 403762306a36Sopenharmony_ci { 0, 64 }, 403862306a36Sopenharmony_ci { 65, 127 }, 403962306a36Sopenharmony_ci { 128, 255 }, 404062306a36Sopenharmony_ci { 256, 511 }, 404162306a36Sopenharmony_ci { 512, 1023 }, 404262306a36Sopenharmony_ci { 1024, 1518 }, 404362306a36Sopenharmony_ci { 1519, 2047 }, 404462306a36Sopenharmony_ci { 2048, 4095 }, 404562306a36Sopenharmony_ci { 4096, 9216 }, 404662306a36Sopenharmony_ci { 9217, 16383 }, 404762306a36Sopenharmony_ci {} 404862306a36Sopenharmony_ci}; 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_cistatic void bnxt_get_rmon_stats(struct net_device *dev, 405162306a36Sopenharmony_ci struct ethtool_rmon_stats *rmon_stats, 405262306a36Sopenharmony_ci const struct ethtool_rmon_hist_range **ranges) 405362306a36Sopenharmony_ci{ 405462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 405562306a36Sopenharmony_ci u64 *rx, *tx; 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 405862306a36Sopenharmony_ci return; 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci rx = bp->port_stats.sw_stats; 406162306a36Sopenharmony_ci tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci rmon_stats->jabbers = 406462306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 406562306a36Sopenharmony_ci rmon_stats->oversize_pkts = 406662306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 406762306a36Sopenharmony_ci rmon_stats->undersize_pkts = 406862306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 407162306a36Sopenharmony_ci rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 407262306a36Sopenharmony_ci rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 407362306a36Sopenharmony_ci rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 407462306a36Sopenharmony_ci rmon_stats->hist[4] = 407562306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 407662306a36Sopenharmony_ci rmon_stats->hist[5] = 407762306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 407862306a36Sopenharmony_ci rmon_stats->hist[6] = 407962306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 408062306a36Sopenharmony_ci rmon_stats->hist[7] = 408162306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 408262306a36Sopenharmony_ci rmon_stats->hist[8] = 408362306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 408462306a36Sopenharmony_ci rmon_stats->hist[9] = 408562306a36Sopenharmony_ci BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci rmon_stats->hist_tx[0] = 408862306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 408962306a36Sopenharmony_ci rmon_stats->hist_tx[1] = 409062306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 409162306a36Sopenharmony_ci rmon_stats->hist_tx[2] = 409262306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 409362306a36Sopenharmony_ci rmon_stats->hist_tx[3] = 409462306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 409562306a36Sopenharmony_ci rmon_stats->hist_tx[4] = 409662306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 409762306a36Sopenharmony_ci rmon_stats->hist_tx[5] = 409862306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 409962306a36Sopenharmony_ci rmon_stats->hist_tx[6] = 410062306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 410162306a36Sopenharmony_ci rmon_stats->hist_tx[7] = 410262306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 410362306a36Sopenharmony_ci rmon_stats->hist_tx[8] = 410462306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 410562306a36Sopenharmony_ci rmon_stats->hist_tx[9] = 410662306a36Sopenharmony_ci BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 410762306a36Sopenharmony_ci 410862306a36Sopenharmony_ci *ranges = bnxt_rmon_ranges; 410962306a36Sopenharmony_ci} 411062306a36Sopenharmony_ci 411162306a36Sopenharmony_cistatic void bnxt_get_link_ext_stats(struct net_device *dev, 411262306a36Sopenharmony_ci struct ethtool_link_ext_stats *stats) 411362306a36Sopenharmony_ci{ 411462306a36Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 411562306a36Sopenharmony_ci u64 *rx; 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 411862306a36Sopenharmony_ci return; 411962306a36Sopenharmony_ci 412062306a36Sopenharmony_ci rx = bp->rx_port_stats_ext.sw_stats; 412162306a36Sopenharmony_ci stats->link_down_events = 412262306a36Sopenharmony_ci *(rx + BNXT_RX_STATS_EXT_OFFSET(link_down_events)); 412362306a36Sopenharmony_ci} 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_civoid bnxt_ethtool_free(struct bnxt *bp) 412662306a36Sopenharmony_ci{ 412762306a36Sopenharmony_ci kfree(bp->test_info); 412862306a36Sopenharmony_ci bp->test_info = NULL; 412962306a36Sopenharmony_ci} 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ciconst struct ethtool_ops bnxt_ethtool_ops = { 413262306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 413362306a36Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 413462306a36Sopenharmony_ci ETHTOOL_COALESCE_USECS_IRQ | 413562306a36Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 413662306a36Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS | 413762306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 413862306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_CQE, 413962306a36Sopenharmony_ci .get_link_ksettings = bnxt_get_link_ksettings, 414062306a36Sopenharmony_ci .set_link_ksettings = bnxt_set_link_ksettings, 414162306a36Sopenharmony_ci .get_fec_stats = bnxt_get_fec_stats, 414262306a36Sopenharmony_ci .get_fecparam = bnxt_get_fecparam, 414362306a36Sopenharmony_ci .set_fecparam = bnxt_set_fecparam, 414462306a36Sopenharmony_ci .get_pause_stats = bnxt_get_pause_stats, 414562306a36Sopenharmony_ci .get_pauseparam = bnxt_get_pauseparam, 414662306a36Sopenharmony_ci .set_pauseparam = bnxt_set_pauseparam, 414762306a36Sopenharmony_ci .get_drvinfo = bnxt_get_drvinfo, 414862306a36Sopenharmony_ci .get_regs_len = bnxt_get_regs_len, 414962306a36Sopenharmony_ci .get_regs = bnxt_get_regs, 415062306a36Sopenharmony_ci .get_wol = bnxt_get_wol, 415162306a36Sopenharmony_ci .set_wol = bnxt_set_wol, 415262306a36Sopenharmony_ci .get_coalesce = bnxt_get_coalesce, 415362306a36Sopenharmony_ci .set_coalesce = bnxt_set_coalesce, 415462306a36Sopenharmony_ci .get_msglevel = bnxt_get_msglevel, 415562306a36Sopenharmony_ci .set_msglevel = bnxt_set_msglevel, 415662306a36Sopenharmony_ci .get_sset_count = bnxt_get_sset_count, 415762306a36Sopenharmony_ci .get_strings = bnxt_get_strings, 415862306a36Sopenharmony_ci .get_ethtool_stats = bnxt_get_ethtool_stats, 415962306a36Sopenharmony_ci .set_ringparam = bnxt_set_ringparam, 416062306a36Sopenharmony_ci .get_ringparam = bnxt_get_ringparam, 416162306a36Sopenharmony_ci .get_channels = bnxt_get_channels, 416262306a36Sopenharmony_ci .set_channels = bnxt_set_channels, 416362306a36Sopenharmony_ci .get_rxnfc = bnxt_get_rxnfc, 416462306a36Sopenharmony_ci .set_rxnfc = bnxt_set_rxnfc, 416562306a36Sopenharmony_ci .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 416662306a36Sopenharmony_ci .get_rxfh_key_size = bnxt_get_rxfh_key_size, 416762306a36Sopenharmony_ci .get_rxfh = bnxt_get_rxfh, 416862306a36Sopenharmony_ci .set_rxfh = bnxt_set_rxfh, 416962306a36Sopenharmony_ci .flash_device = bnxt_flash_device, 417062306a36Sopenharmony_ci .get_eeprom_len = bnxt_get_eeprom_len, 417162306a36Sopenharmony_ci .get_eeprom = bnxt_get_eeprom, 417262306a36Sopenharmony_ci .set_eeprom = bnxt_set_eeprom, 417362306a36Sopenharmony_ci .get_link = bnxt_get_link, 417462306a36Sopenharmony_ci .get_link_ext_stats = bnxt_get_link_ext_stats, 417562306a36Sopenharmony_ci .get_eee = bnxt_get_eee, 417662306a36Sopenharmony_ci .set_eee = bnxt_set_eee, 417762306a36Sopenharmony_ci .get_module_info = bnxt_get_module_info, 417862306a36Sopenharmony_ci .get_module_eeprom = bnxt_get_module_eeprom, 417962306a36Sopenharmony_ci .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, 418062306a36Sopenharmony_ci .nway_reset = bnxt_nway_reset, 418162306a36Sopenharmony_ci .set_phys_id = bnxt_set_phys_id, 418262306a36Sopenharmony_ci .self_test = bnxt_self_test, 418362306a36Sopenharmony_ci .get_ts_info = bnxt_get_ts_info, 418462306a36Sopenharmony_ci .reset = bnxt_reset, 418562306a36Sopenharmony_ci .set_dump = bnxt_set_dump, 418662306a36Sopenharmony_ci .get_dump_flag = bnxt_get_dump_flag, 418762306a36Sopenharmony_ci .get_dump_data = bnxt_get_dump_data, 418862306a36Sopenharmony_ci .get_eth_phy_stats = bnxt_get_eth_phy_stats, 418962306a36Sopenharmony_ci .get_eth_mac_stats = bnxt_get_eth_mac_stats, 419062306a36Sopenharmony_ci .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 419162306a36Sopenharmony_ci .get_rmon_stats = bnxt_get_rmon_stats, 419262306a36Sopenharmony_ci}; 4193