18c2ecf20Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Broadcom Limited 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/ctype.h> 128c2ecf20Sopenharmony_ci#include <linux/stringify.h> 138c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 148c2ecf20Sopenharmony_ci#include <linux/linkmode.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/pci.h> 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/crc32.h> 198c2ecf20Sopenharmony_ci#include <linux/firmware.h> 208c2ecf20Sopenharmony_ci#include <linux/utsname.h> 218c2ecf20Sopenharmony_ci#include <linux/time.h> 228c2ecf20Sopenharmony_ci#include "bnxt_hsi.h" 238c2ecf20Sopenharmony_ci#include "bnxt.h" 248c2ecf20Sopenharmony_ci#include "bnxt_xdp.h" 258c2ecf20Sopenharmony_ci#include "bnxt_ethtool.h" 268c2ecf20Sopenharmony_ci#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ 278c2ecf20Sopenharmony_ci#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ 288c2ecf20Sopenharmony_ci#include "bnxt_coredump.h" 298c2ecf20Sopenharmony_ci#define FLASH_NVRAM_TIMEOUT ((HWRM_CMD_TIMEOUT) * 100) 308c2ecf20Sopenharmony_ci#define FLASH_PACKAGE_TIMEOUT ((HWRM_CMD_TIMEOUT) * 200) 318c2ecf20Sopenharmony_ci#define INSTALL_PACKAGE_TIMEOUT ((HWRM_CMD_TIMEOUT) * 200) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic u32 bnxt_get_msglevel(struct net_device *dev) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return bp->msg_enable; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void bnxt_set_msglevel(struct net_device *dev, u32 value) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci bp->msg_enable = value; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic int bnxt_get_coalesce(struct net_device *dev, 488c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 518c2ecf20Sopenharmony_ci struct bnxt_coal *hw_coal; 528c2ecf20Sopenharmony_ci u16 mult; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci memset(coal, 0, sizeof(*coal)); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci hw_coal = &bp->rx_coal; 598c2ecf20Sopenharmony_ci mult = hw_coal->bufs_per_record; 608c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs = hw_coal->coal_ticks; 618c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; 628c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 638c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci hw_coal = &bp->tx_coal; 668c2ecf20Sopenharmony_ci mult = hw_coal->bufs_per_record; 678c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs = hw_coal->coal_ticks; 688c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; 698c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 708c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int bnxt_set_coalesce(struct net_device *dev, 788c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 818c2ecf20Sopenharmony_ci bool update_stats = false; 828c2ecf20Sopenharmony_ci struct bnxt_coal *hw_coal; 838c2ecf20Sopenharmony_ci int rc = 0; 848c2ecf20Sopenharmony_ci u16 mult; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (coal->use_adaptive_rx_coalesce) { 878c2ecf20Sopenharmony_ci bp->flags |= BNXT_FLAG_DIM; 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_DIM) { 908c2ecf20Sopenharmony_ci bp->flags &= ~(BNXT_FLAG_DIM); 918c2ecf20Sopenharmony_ci goto reset_coalesce; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci hw_coal = &bp->rx_coal; 968c2ecf20Sopenharmony_ci mult = hw_coal->bufs_per_record; 978c2ecf20Sopenharmony_ci hw_coal->coal_ticks = coal->rx_coalesce_usecs; 988c2ecf20Sopenharmony_ci hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; 998c2ecf20Sopenharmony_ci hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; 1008c2ecf20Sopenharmony_ci hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci hw_coal = &bp->tx_coal; 1038c2ecf20Sopenharmony_ci mult = hw_coal->bufs_per_record; 1048c2ecf20Sopenharmony_ci hw_coal->coal_ticks = coal->tx_coalesce_usecs; 1058c2ecf20Sopenharmony_ci hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; 1068c2ecf20Sopenharmony_ci hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; 1078c2ecf20Sopenharmony_ci hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { 1108c2ecf20Sopenharmony_ci u32 stats_ticks = coal->stats_block_coalesce_usecs; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Allow 0, which means disable. */ 1138c2ecf20Sopenharmony_ci if (stats_ticks) 1148c2ecf20Sopenharmony_ci stats_ticks = clamp_t(u32, stats_ticks, 1158c2ecf20Sopenharmony_ci BNXT_MIN_STATS_COAL_TICKS, 1168c2ecf20Sopenharmony_ci BNXT_MAX_STATS_COAL_TICKS); 1178c2ecf20Sopenharmony_ci stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); 1188c2ecf20Sopenharmony_ci bp->stats_coal_ticks = stats_ticks; 1198c2ecf20Sopenharmony_ci if (bp->stats_coal_ticks) 1208c2ecf20Sopenharmony_ci bp->current_interval = 1218c2ecf20Sopenharmony_ci bp->stats_coal_ticks * HZ / 1000000; 1228c2ecf20Sopenharmony_ci else 1238c2ecf20Sopenharmony_ci bp->current_interval = BNXT_TIMER_INTERVAL; 1248c2ecf20Sopenharmony_ci update_stats = true; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cireset_coalesce: 1288c2ecf20Sopenharmony_ci if (test_bit(BNXT_STATE_OPEN, &bp->state)) { 1298c2ecf20Sopenharmony_ci if (update_stats) { 1308c2ecf20Sopenharmony_ci rc = bnxt_close_nic(bp, true, false); 1318c2ecf20Sopenharmony_ci if (!rc) 1328c2ecf20Sopenharmony_ci rc = bnxt_open_nic(bp, true, false); 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci rc = bnxt_hwrm_set_coal(bp); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return rc; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_rx_stats_str[] = { 1428c2ecf20Sopenharmony_ci "rx_ucast_packets", 1438c2ecf20Sopenharmony_ci "rx_mcast_packets", 1448c2ecf20Sopenharmony_ci "rx_bcast_packets", 1458c2ecf20Sopenharmony_ci "rx_discards", 1468c2ecf20Sopenharmony_ci "rx_errors", 1478c2ecf20Sopenharmony_ci "rx_ucast_bytes", 1488c2ecf20Sopenharmony_ci "rx_mcast_bytes", 1498c2ecf20Sopenharmony_ci "rx_bcast_bytes", 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tx_stats_str[] = { 1538c2ecf20Sopenharmony_ci "tx_ucast_packets", 1548c2ecf20Sopenharmony_ci "tx_mcast_packets", 1558c2ecf20Sopenharmony_ci "tx_bcast_packets", 1568c2ecf20Sopenharmony_ci "tx_errors", 1578c2ecf20Sopenharmony_ci "tx_discards", 1588c2ecf20Sopenharmony_ci "tx_ucast_bytes", 1598c2ecf20Sopenharmony_ci "tx_mcast_bytes", 1608c2ecf20Sopenharmony_ci "tx_bcast_bytes", 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tpa_stats_str[] = { 1648c2ecf20Sopenharmony_ci "tpa_packets", 1658c2ecf20Sopenharmony_ci "tpa_bytes", 1668c2ecf20Sopenharmony_ci "tpa_events", 1678c2ecf20Sopenharmony_ci "tpa_aborts", 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tpa2_stats_str[] = { 1718c2ecf20Sopenharmony_ci "rx_tpa_eligible_pkt", 1728c2ecf20Sopenharmony_ci "rx_tpa_eligible_bytes", 1738c2ecf20Sopenharmony_ci "rx_tpa_pkt", 1748c2ecf20Sopenharmony_ci "rx_tpa_bytes", 1758c2ecf20Sopenharmony_ci "rx_tpa_errors", 1768c2ecf20Sopenharmony_ci "rx_tpa_events", 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const char * const bnxt_rx_sw_stats_str[] = { 1808c2ecf20Sopenharmony_ci "rx_l4_csum_errors", 1818c2ecf20Sopenharmony_ci "rx_resets", 1828c2ecf20Sopenharmony_ci "rx_buf_errors", 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic const char * const bnxt_cmn_sw_stats_str[] = { 1868c2ecf20Sopenharmony_ci "missed_irqs", 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_ENTRY(counter) \ 1908c2ecf20Sopenharmony_ci { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_ENTRY(counter) \ 1938c2ecf20Sopenharmony_ci { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_ENTRY(counter) \ 1968c2ecf20Sopenharmony_ci { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_ENTRY(counter) \ 1998c2ecf20Sopenharmony_ci { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ 2028c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ 2038c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ 2068c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ 2078c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRIES \ 2108c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ 2118c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ 2128c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ 2138c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ 2148c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ 2158c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ 2168c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ 2178c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRY(7) 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRIES \ 2208c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ 2218c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ 2228c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ 2238c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ 2248c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ 2258c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ 2268c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ 2278c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRY(7) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ 2308c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ 2318c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ 2348c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ 2358c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRIES \ 2388c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(0), \ 2398c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(1), \ 2408c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(2), \ 2418c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(3), \ 2428c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(4), \ 2438c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(5), \ 2448c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(6), \ 2458c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRY(7) \ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRIES \ 2488c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(0), \ 2498c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(1), \ 2508c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(2), \ 2518c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(3), \ 2528c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(4), \ 2538c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(5), \ 2548c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(6), \ 2558c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRY(7) \ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ 2588c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ 2598c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ 2628c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ 2638c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ 2648c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ 2658c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ 2668c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ 2678c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ 2688c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ 2698c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ 2728c2ecf20Sopenharmony_ci { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ 2738c2ecf20Sopenharmony_ci __stringify(counter##_pri##n) } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ 2768c2ecf20Sopenharmony_ci { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ 2778c2ecf20Sopenharmony_ci __stringify(counter##_pri##n) } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRIES(counter) \ 2808c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ 2818c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ 2828c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ 2838c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ 2848c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ 2858c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ 2868c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ 2878c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRY(counter, 7) 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRIES(counter) \ 2908c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ 2918c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ 2928c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ 2938c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ 2948c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ 2958c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ 2968c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ 2978c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRY(counter, 7) 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cienum { 3008c2ecf20Sopenharmony_ci RX_TOTAL_DISCARDS, 3018c2ecf20Sopenharmony_ci TX_TOTAL_DISCARDS, 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic struct { 3058c2ecf20Sopenharmony_ci u64 counter; 3068c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 3078c2ecf20Sopenharmony_ci} bnxt_sw_func_stats[] = { 3088c2ecf20Sopenharmony_ci {0, "rx_total_discard_pkts"}, 3098c2ecf20Sopenharmony_ci {0, "tx_total_discard_pkts"}, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci#define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) 3138c2ecf20Sopenharmony_ci#define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) 3148c2ecf20Sopenharmony_ci#define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) 3158c2ecf20Sopenharmony_ci#define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const struct { 3188c2ecf20Sopenharmony_ci long offset; 3198c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 3208c2ecf20Sopenharmony_ci} bnxt_port_stats_arr[] = { 3218c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_64b_frames), 3228c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), 3238c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), 3248c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), 3258c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), 3268c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), 3278c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), 3288c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), 3298c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), 3308c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), 3318c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), 3328c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_total_frames), 3338c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ucast_frames), 3348c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_mcast_frames), 3358c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_bcast_frames), 3368c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), 3378c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ctrl_frames), 3388c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pause_frames), 3398c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_frames), 3408c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_align_err_frames), 3418c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), 3428c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_jbr_frames), 3438c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), 3448c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_tagged_frames), 3458c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), 3468c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_good_frames), 3478c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), 3488c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), 3498c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), 3508c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), 3518c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), 3528c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), 3538c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), 3548c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), 3558c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_undrsz_frames), 3568c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), 3578c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), 3588c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_bytes), 3598c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_runt_bytes), 3608c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_runt_frames), 3618c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_stat_discard), 3628c2ecf20Sopenharmony_ci BNXT_RX_STATS_ENTRY(rx_stat_err), 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_64b_frames), 3658c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), 3668c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), 3678c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), 3688c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), 3698c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), 3708c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), 3718c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), 3728c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), 3738c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), 3748c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), 3758c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_good_frames), 3768c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_total_frames), 3778c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_ucast_frames), 3788c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_mcast_frames), 3798c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_bcast_frames), 3808c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pause_frames), 3818c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_frames), 3828c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_jabber_frames), 3838c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), 3848c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_err), 3858c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_fifo_underruns), 3868c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), 3878c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), 3888c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), 3898c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), 3908c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), 3918c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), 3928c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), 3938c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), 3948c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), 3958c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), 3968c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_total_collisions), 3978c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_bytes), 3988c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_xthol_frames), 3998c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_stat_discard), 4008c2ecf20Sopenharmony_ci BNXT_TX_STATS_ENTRY(tx_stat_error), 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic const struct { 4048c2ecf20Sopenharmony_ci long offset; 4058c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4068c2ecf20Sopenharmony_ci} bnxt_port_stats_ext_arr[] = { 4078c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(link_down_events), 4088c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), 4098c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), 4108c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), 4118c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), 4128c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_COS_ENTRIES, 4138c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_PFC_ENTRIES, 4148c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_bits), 4158c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), 4168c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), 4178c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), 4188c2ecf20Sopenharmony_ci BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic const struct { 4228c2ecf20Sopenharmony_ci long offset; 4238c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4248c2ecf20Sopenharmony_ci} bnxt_tx_port_stats_ext_arr[] = { 4258c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_COS_ENTRIES, 4268c2ecf20Sopenharmony_ci BNXT_TX_STATS_EXT_PFC_ENTRIES, 4278c2ecf20Sopenharmony_ci}; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic const struct { 4308c2ecf20Sopenharmony_ci long base_off; 4318c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4328c2ecf20Sopenharmony_ci} bnxt_rx_bytes_pri_arr[] = { 4338c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), 4348c2ecf20Sopenharmony_ci}; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic const struct { 4378c2ecf20Sopenharmony_ci long base_off; 4388c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4398c2ecf20Sopenharmony_ci} bnxt_rx_pkts_pri_arr[] = { 4408c2ecf20Sopenharmony_ci BNXT_RX_STATS_PRI_ENTRIES(rx_packets), 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic const struct { 4448c2ecf20Sopenharmony_ci long base_off; 4458c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4468c2ecf20Sopenharmony_ci} bnxt_tx_bytes_pri_arr[] = { 4478c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), 4488c2ecf20Sopenharmony_ci}; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic const struct { 4518c2ecf20Sopenharmony_ci long base_off; 4528c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 4538c2ecf20Sopenharmony_ci} bnxt_tx_pkts_pri_arr[] = { 4548c2ecf20Sopenharmony_ci BNXT_TX_STATS_PRI_ENTRIES(tx_packets), 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci#define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats) 4588c2ecf20Sopenharmony_ci#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) 4598c2ecf20Sopenharmony_ci#define BNXT_NUM_STATS_PRI \ 4608c2ecf20Sopenharmony_ci (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ 4618c2ecf20Sopenharmony_ci ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ 4628c2ecf20Sopenharmony_ci ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ 4638c2ecf20Sopenharmony_ci ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci if (BNXT_SUPPORTS_TPA(bp)) { 4688c2ecf20Sopenharmony_ci if (bp->max_tpa_v2) { 4698c2ecf20Sopenharmony_ci if (BNXT_CHIP_P5_THOR(bp)) 4708c2ecf20Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS_P5; 4718c2ecf20Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS_P5_SR2; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci return BNXT_NUM_TPA_RING_STATS; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int bnxt_get_num_ring_stats(struct bnxt *bp) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci int rx, tx, cmn; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + 4838c2ecf20Sopenharmony_ci bnxt_get_num_tpa_ring_stats(bp); 4848c2ecf20Sopenharmony_ci tx = NUM_RING_TX_HW_STATS; 4858c2ecf20Sopenharmony_ci cmn = NUM_RING_CMN_SW_STATS; 4868c2ecf20Sopenharmony_ci return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + 4878c2ecf20Sopenharmony_ci cmn * bp->cp_nr_rings; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int bnxt_get_num_stats(struct bnxt *bp) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci int num_stats = bnxt_get_num_ring_stats(bp); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci num_stats += BNXT_NUM_SW_FUNC_STATS; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) 4978c2ecf20Sopenharmony_ci num_stats += BNXT_NUM_PORT_STATS; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 5008c2ecf20Sopenharmony_ci num_stats += bp->fw_rx_stats_ext_size + 5018c2ecf20Sopenharmony_ci bp->fw_tx_stats_ext_size; 5028c2ecf20Sopenharmony_ci if (bp->pri2cos_valid) 5038c2ecf20Sopenharmony_ci num_stats += BNXT_NUM_STATS_PRI; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return num_stats; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int bnxt_get_sset_count(struct net_device *dev, int sset) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci switch (sset) { 5148c2ecf20Sopenharmony_ci case ETH_SS_STATS: 5158c2ecf20Sopenharmony_ci return bnxt_get_num_stats(bp); 5168c2ecf20Sopenharmony_ci case ETH_SS_TEST: 5178c2ecf20Sopenharmony_ci if (!bp->num_tests) 5188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5198c2ecf20Sopenharmony_ci return bp->num_tests; 5208c2ecf20Sopenharmony_ci default: 5218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic bool is_rx_ring(struct bnxt *bp, int ring_num) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci return ring_num < bp->rx_nr_rings; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic bool is_tx_ring(struct bnxt *bp, int ring_num) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci int tx_base = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) 5358c2ecf20Sopenharmony_ci tx_base = bp->rx_nr_rings; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) 5388c2ecf20Sopenharmony_ci return true; 5398c2ecf20Sopenharmony_ci return false; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic void bnxt_get_ethtool_stats(struct net_device *dev, 5438c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci u32 i, j = 0; 5468c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 5478c2ecf20Sopenharmony_ci u32 tpa_stats; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!bp->bnapi) { 5508c2ecf20Sopenharmony_ci j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS; 5518c2ecf20Sopenharmony_ci goto skip_ring_stats; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) 5558c2ecf20Sopenharmony_ci bnxt_sw_func_stats[i].counter = 0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci tpa_stats = bnxt_get_num_tpa_ring_stats(bp); 5588c2ecf20Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 5598c2ecf20Sopenharmony_ci struct bnxt_napi *bnapi = bp->bnapi[i]; 5608c2ecf20Sopenharmony_ci struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; 5618c2ecf20Sopenharmony_ci u64 *sw_stats = cpr->stats.sw_stats; 5628c2ecf20Sopenharmony_ci u64 *sw; 5638c2ecf20Sopenharmony_ci int k; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (is_rx_ring(bp, i)) { 5668c2ecf20Sopenharmony_ci for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) 5678c2ecf20Sopenharmony_ci buf[j] = sw_stats[k]; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci if (is_tx_ring(bp, i)) { 5708c2ecf20Sopenharmony_ci k = NUM_RING_RX_HW_STATS; 5718c2ecf20Sopenharmony_ci for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 5728c2ecf20Sopenharmony_ci j++, k++) 5738c2ecf20Sopenharmony_ci buf[j] = sw_stats[k]; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci if (!tpa_stats || !is_rx_ring(bp, i)) 5768c2ecf20Sopenharmony_ci goto skip_tpa_ring_stats; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 5798c2ecf20Sopenharmony_ci for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + 5808c2ecf20Sopenharmony_ci tpa_stats; j++, k++) 5818c2ecf20Sopenharmony_ci buf[j] = sw_stats[k]; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ciskip_tpa_ring_stats: 5848c2ecf20Sopenharmony_ci sw = (u64 *)&cpr->sw_stats.rx; 5858c2ecf20Sopenharmony_ci if (is_rx_ring(bp, i)) { 5868c2ecf20Sopenharmony_ci for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) 5878c2ecf20Sopenharmony_ci buf[j] = sw[k]; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci sw = (u64 *)&cpr->sw_stats.cmn; 5918c2ecf20Sopenharmony_ci for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) 5928c2ecf20Sopenharmony_ci buf[j] = sw[k]; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += 5958c2ecf20Sopenharmony_ci BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts); 5968c2ecf20Sopenharmony_ci bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter += 5978c2ecf20Sopenharmony_ci BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts); 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++) 6018c2ecf20Sopenharmony_ci buf[j] = bnxt_sw_func_stats[i].counter; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciskip_ring_stats: 6048c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) { 6058c2ecf20Sopenharmony_ci u64 *port_stats = bp->port_stats.sw_stats; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) 6088c2ecf20Sopenharmony_ci buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 6118c2ecf20Sopenharmony_ci u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; 6128c2ecf20Sopenharmony_ci u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { 6158c2ecf20Sopenharmony_ci buf[j] = *(rx_port_stats_ext + 6168c2ecf20Sopenharmony_ci bnxt_port_stats_ext_arr[i].offset); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { 6198c2ecf20Sopenharmony_ci buf[j] = *(tx_port_stats_ext + 6208c2ecf20Sopenharmony_ci bnxt_tx_port_stats_ext_arr[i].offset); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci if (bp->pri2cos_valid) { 6238c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 6248c2ecf20Sopenharmony_ci long n = bnxt_rx_bytes_pri_arr[i].base_off + 6258c2ecf20Sopenharmony_ci bp->pri2cos_idx[i]; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci buf[j] = *(rx_port_stats_ext + n); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 6308c2ecf20Sopenharmony_ci long n = bnxt_rx_pkts_pri_arr[i].base_off + 6318c2ecf20Sopenharmony_ci bp->pri2cos_idx[i]; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci buf[j] = *(rx_port_stats_ext + n); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 6368c2ecf20Sopenharmony_ci long n = bnxt_tx_bytes_pri_arr[i].base_off + 6378c2ecf20Sopenharmony_ci bp->pri2cos_idx[i]; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci buf[j] = *(tx_port_stats_ext + n); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, j++) { 6428c2ecf20Sopenharmony_ci long n = bnxt_tx_pkts_pri_arr[i].base_off + 6438c2ecf20Sopenharmony_ci bp->pri2cos_idx[i]; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci buf[j] = *(tx_port_stats_ext + n); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 6548c2ecf20Sopenharmony_ci static const char * const *str; 6558c2ecf20Sopenharmony_ci u32 i, j, num_str; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci switch (stringset) { 6588c2ecf20Sopenharmony_ci case ETH_SS_STATS: 6598c2ecf20Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 6608c2ecf20Sopenharmony_ci if (is_rx_ring(bp, i)) { 6618c2ecf20Sopenharmony_ci num_str = NUM_RING_RX_HW_STATS; 6628c2ecf20Sopenharmony_ci for (j = 0; j < num_str; j++) { 6638c2ecf20Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 6648c2ecf20Sopenharmony_ci bnxt_ring_rx_stats_str[j]); 6658c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if (is_tx_ring(bp, i)) { 6698c2ecf20Sopenharmony_ci num_str = NUM_RING_TX_HW_STATS; 6708c2ecf20Sopenharmony_ci for (j = 0; j < num_str; j++) { 6718c2ecf20Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 6728c2ecf20Sopenharmony_ci bnxt_ring_tx_stats_str[j]); 6738c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci num_str = bnxt_get_num_tpa_ring_stats(bp); 6778c2ecf20Sopenharmony_ci if (!num_str || !is_rx_ring(bp, i)) 6788c2ecf20Sopenharmony_ci goto skip_tpa_stats; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (bp->max_tpa_v2) 6818c2ecf20Sopenharmony_ci str = bnxt_ring_tpa2_stats_str; 6828c2ecf20Sopenharmony_ci else 6838c2ecf20Sopenharmony_ci str = bnxt_ring_tpa_stats_str; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci for (j = 0; j < num_str; j++) { 6868c2ecf20Sopenharmony_ci sprintf(buf, "[%d]: %s", i, str[j]); 6878c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ciskip_tpa_stats: 6908c2ecf20Sopenharmony_ci if (is_rx_ring(bp, i)) { 6918c2ecf20Sopenharmony_ci num_str = NUM_RING_RX_SW_STATS; 6928c2ecf20Sopenharmony_ci for (j = 0; j < num_str; j++) { 6938c2ecf20Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 6948c2ecf20Sopenharmony_ci bnxt_rx_sw_stats_str[j]); 6958c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci num_str = NUM_RING_CMN_SW_STATS; 6998c2ecf20Sopenharmony_ci for (j = 0; j < num_str; j++) { 7008c2ecf20Sopenharmony_ci sprintf(buf, "[%d]: %s", i, 7018c2ecf20Sopenharmony_ci bnxt_cmn_sw_stats_str[j]); 7028c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) { 7068c2ecf20Sopenharmony_ci strcpy(buf, bnxt_sw_func_stats[i].string); 7078c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS) { 7118c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { 7128c2ecf20Sopenharmony_ci strcpy(buf, bnxt_port_stats_arr[i].string); 7138c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 7178c2ecf20Sopenharmony_ci for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { 7188c2ecf20Sopenharmony_ci strcpy(buf, bnxt_port_stats_ext_arr[i].string); 7198c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { 7228c2ecf20Sopenharmony_ci strcpy(buf, 7238c2ecf20Sopenharmony_ci bnxt_tx_port_stats_ext_arr[i].string); 7248c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci if (bp->pri2cos_valid) { 7278c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 7288c2ecf20Sopenharmony_ci strcpy(buf, 7298c2ecf20Sopenharmony_ci bnxt_rx_bytes_pri_arr[i].string); 7308c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 7338c2ecf20Sopenharmony_ci strcpy(buf, 7348c2ecf20Sopenharmony_ci bnxt_rx_pkts_pri_arr[i].string); 7358c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 7388c2ecf20Sopenharmony_ci strcpy(buf, 7398c2ecf20Sopenharmony_ci bnxt_tx_bytes_pri_arr[i].string); 7408c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 7438c2ecf20Sopenharmony_ci strcpy(buf, 7448c2ecf20Sopenharmony_ci bnxt_tx_pkts_pri_arr[i].string); 7458c2ecf20Sopenharmony_ci buf += ETH_GSTRING_LEN; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci case ETH_SS_TEST: 7518c2ecf20Sopenharmony_ci if (bp->num_tests) 7528c2ecf20Sopenharmony_ci memcpy(buf, bp->test_info->string, 7538c2ecf20Sopenharmony_ci bp->num_tests * ETH_GSTRING_LEN); 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci default: 7568c2ecf20Sopenharmony_ci netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", 7578c2ecf20Sopenharmony_ci stringset); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic void bnxt_get_ringparam(struct net_device *dev, 7638c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; 7688c2ecf20Sopenharmony_ci ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; 7698c2ecf20Sopenharmony_ci ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci ering->rx_pending = bp->rx_ring_size; 7728c2ecf20Sopenharmony_ci ering->rx_jumbo_pending = bp->rx_agg_ring_size; 7738c2ecf20Sopenharmony_ci ering->tx_pending = bp->tx_ring_size; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int bnxt_set_ringparam(struct net_device *dev, 7778c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || 7828c2ecf20Sopenharmony_ci (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || 7838c2ecf20Sopenharmony_ci (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) 7848c2ecf20Sopenharmony_ci return -EINVAL; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (netif_running(dev)) 7878c2ecf20Sopenharmony_ci bnxt_close_nic(bp, false, false); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci bp->rx_ring_size = ering->rx_pending; 7908c2ecf20Sopenharmony_ci bp->tx_ring_size = ering->tx_pending; 7918c2ecf20Sopenharmony_ci bnxt_set_ring_params(bp); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (netif_running(dev)) 7948c2ecf20Sopenharmony_ci return bnxt_open_nic(bp, false, false); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void bnxt_get_channels(struct net_device *dev, 8008c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 8038c2ecf20Sopenharmony_ci struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 8048c2ecf20Sopenharmony_ci int max_rx_rings, max_tx_rings, tcs; 8058c2ecf20Sopenharmony_ci int max_tx_sch_inputs, tx_grps; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Get the most up-to-date max_tx_sch_inputs. */ 8088c2ecf20Sopenharmony_ci if (netif_running(dev) && BNXT_NEW_RM(bp)) 8098c2ecf20Sopenharmony_ci bnxt_hwrm_func_resc_qcaps(bp, false); 8108c2ecf20Sopenharmony_ci max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); 8138c2ecf20Sopenharmony_ci if (max_tx_sch_inputs) 8148c2ecf20Sopenharmony_ci max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci tcs = netdev_get_num_tc(dev); 8178c2ecf20Sopenharmony_ci tx_grps = max(tcs, 1); 8188c2ecf20Sopenharmony_ci if (bp->tx_nr_rings_xdp) 8198c2ecf20Sopenharmony_ci tx_grps++; 8208c2ecf20Sopenharmony_ci max_tx_rings /= tx_grps; 8218c2ecf20Sopenharmony_ci channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { 8248c2ecf20Sopenharmony_ci max_rx_rings = 0; 8258c2ecf20Sopenharmony_ci max_tx_rings = 0; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci if (max_tx_sch_inputs) 8288c2ecf20Sopenharmony_ci max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (tcs > 1) 8318c2ecf20Sopenharmony_ci max_tx_rings /= tcs; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci channel->max_rx = max_rx_rings; 8348c2ecf20Sopenharmony_ci channel->max_tx = max_tx_rings; 8358c2ecf20Sopenharmony_ci channel->max_other = 0; 8368c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_SHARED_RINGS) { 8378c2ecf20Sopenharmony_ci channel->combined_count = bp->rx_nr_rings; 8388c2ecf20Sopenharmony_ci if (BNXT_CHIP_TYPE_NITRO_A0(bp)) 8398c2ecf20Sopenharmony_ci channel->combined_count--; 8408c2ecf20Sopenharmony_ci } else { 8418c2ecf20Sopenharmony_ci if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { 8428c2ecf20Sopenharmony_ci channel->rx_count = bp->rx_nr_rings; 8438c2ecf20Sopenharmony_ci channel->tx_count = bp->tx_nr_rings_per_tc; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic int bnxt_set_channels(struct net_device *dev, 8498c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 8528c2ecf20Sopenharmony_ci int req_tx_rings, req_rx_rings, tcs; 8538c2ecf20Sopenharmony_ci bool sh = false; 8548c2ecf20Sopenharmony_ci int tx_xdp = 0; 8558c2ecf20Sopenharmony_ci int rc = 0; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (channel->other_count) 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (!channel->combined_count && 8618c2ecf20Sopenharmony_ci (!channel->rx_count || !channel->tx_count)) 8628c2ecf20Sopenharmony_ci return -EINVAL; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (channel->combined_count && 8658c2ecf20Sopenharmony_ci (channel->rx_count || channel->tx_count)) 8668c2ecf20Sopenharmony_ci return -EINVAL; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || 8698c2ecf20Sopenharmony_ci channel->tx_count)) 8708c2ecf20Sopenharmony_ci return -EINVAL; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (channel->combined_count) 8738c2ecf20Sopenharmony_ci sh = true; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci tcs = netdev_get_num_tc(dev); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci req_tx_rings = sh ? channel->combined_count : channel->tx_count; 8788c2ecf20Sopenharmony_ci req_rx_rings = sh ? channel->combined_count : channel->rx_count; 8798c2ecf20Sopenharmony_ci if (bp->tx_nr_rings_xdp) { 8808c2ecf20Sopenharmony_ci if (!sh) { 8818c2ecf20Sopenharmony_ci netdev_err(dev, "Only combined mode supported when XDP is enabled.\n"); 8828c2ecf20Sopenharmony_ci return -EINVAL; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci tx_xdp = req_rx_rings; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); 8878c2ecf20Sopenharmony_ci if (rc) { 8888c2ecf20Sopenharmony_ci netdev_warn(dev, "Unable to allocate the requested rings\n"); 8898c2ecf20Sopenharmony_ci return rc; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != 8938c2ecf20Sopenharmony_ci bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && 8948c2ecf20Sopenharmony_ci (dev->priv_flags & IFF_RXFH_CONFIGURED)) { 8958c2ecf20Sopenharmony_ci netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n"); 8968c2ecf20Sopenharmony_ci return -EINVAL; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (netif_running(dev)) { 9008c2ecf20Sopenharmony_ci if (BNXT_PF(bp)) { 9018c2ecf20Sopenharmony_ci /* TODO CHIMP_FW: Send message to all VF's 9028c2ecf20Sopenharmony_ci * before PF unload 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci rc = bnxt_close_nic(bp, true, false); 9068c2ecf20Sopenharmony_ci if (rc) { 9078c2ecf20Sopenharmony_ci netdev_err(bp->dev, "Set channel failure rc :%x\n", 9088c2ecf20Sopenharmony_ci rc); 9098c2ecf20Sopenharmony_ci return rc; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (sh) { 9148c2ecf20Sopenharmony_ci bp->flags |= BNXT_FLAG_SHARED_RINGS; 9158c2ecf20Sopenharmony_ci bp->rx_nr_rings = channel->combined_count; 9168c2ecf20Sopenharmony_ci bp->tx_nr_rings_per_tc = channel->combined_count; 9178c2ecf20Sopenharmony_ci } else { 9188c2ecf20Sopenharmony_ci bp->flags &= ~BNXT_FLAG_SHARED_RINGS; 9198c2ecf20Sopenharmony_ci bp->rx_nr_rings = channel->rx_count; 9208c2ecf20Sopenharmony_ci bp->tx_nr_rings_per_tc = channel->tx_count; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci bp->tx_nr_rings_xdp = tx_xdp; 9238c2ecf20Sopenharmony_ci bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; 9248c2ecf20Sopenharmony_ci if (tcs > 1) 9258c2ecf20Sopenharmony_ci bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : 9288c2ecf20Sopenharmony_ci bp->tx_nr_rings + bp->rx_nr_rings; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* After changing number of rx channels, update NTUPLE feature. */ 9318c2ecf20Sopenharmony_ci netdev_update_features(dev); 9328c2ecf20Sopenharmony_ci if (netif_running(dev)) { 9338c2ecf20Sopenharmony_ci rc = bnxt_open_nic(bp, true, false); 9348c2ecf20Sopenharmony_ci if ((!rc) && BNXT_PF(bp)) { 9358c2ecf20Sopenharmony_ci /* TODO CHIMP_FW: Send message to all VF's 9368c2ecf20Sopenharmony_ci * to renable 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } else { 9408c2ecf20Sopenharmony_ci rc = bnxt_reserve_rings(bp, true); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci return rc; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 9478c2ecf20Sopenharmony_cistatic int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, 9488c2ecf20Sopenharmony_ci u32 *rule_locs) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci int i, j = 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci cmd->data = bp->ntp_fltr_count; 9538c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 9548c2ecf20Sopenharmony_ci struct hlist_head *head; 9558c2ecf20Sopenharmony_ci struct bnxt_ntuple_filter *fltr; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci head = &bp->ntp_fltr_hash_tbl[i]; 9588c2ecf20Sopenharmony_ci rcu_read_lock(); 9598c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(fltr, head, hash) { 9608c2ecf20Sopenharmony_ci if (j == cmd->rule_cnt) 9618c2ecf20Sopenharmony_ci break; 9628c2ecf20Sopenharmony_ci rule_locs[j++] = fltr->sw_id; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci rcu_read_unlock(); 9658c2ecf20Sopenharmony_ci if (j == cmd->rule_cnt) 9668c2ecf20Sopenharmony_ci break; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci cmd->rule_cnt = j; 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec *fs = 9758c2ecf20Sopenharmony_ci (struct ethtool_rx_flow_spec *)&cmd->fs; 9768c2ecf20Sopenharmony_ci struct bnxt_ntuple_filter *fltr; 9778c2ecf20Sopenharmony_ci struct flow_keys *fkeys; 9788c2ecf20Sopenharmony_ci int i, rc = -EINVAL; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) 9818c2ecf20Sopenharmony_ci return rc; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 9848c2ecf20Sopenharmony_ci struct hlist_head *head; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci head = &bp->ntp_fltr_hash_tbl[i]; 9878c2ecf20Sopenharmony_ci rcu_read_lock(); 9888c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(fltr, head, hash) { 9898c2ecf20Sopenharmony_ci if (fltr->sw_id == fs->location) 9908c2ecf20Sopenharmony_ci goto fltr_found; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci rcu_read_unlock(); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci return rc; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cifltr_found: 9978c2ecf20Sopenharmony_ci fkeys = &fltr->fkeys; 9988c2ecf20Sopenharmony_ci if (fkeys->basic.n_proto == htons(ETH_P_IP)) { 9998c2ecf20Sopenharmony_ci if (fkeys->basic.ip_proto == IPPROTO_TCP) 10008c2ecf20Sopenharmony_ci fs->flow_type = TCP_V4_FLOW; 10018c2ecf20Sopenharmony_ci else if (fkeys->basic.ip_proto == IPPROTO_UDP) 10028c2ecf20Sopenharmony_ci fs->flow_type = UDP_V4_FLOW; 10038c2ecf20Sopenharmony_ci else 10048c2ecf20Sopenharmony_ci goto fltr_err; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; 10078c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; 10108c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; 10138c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; 10168c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); 10178c2ecf20Sopenharmony_ci } else { 10188c2ecf20Sopenharmony_ci int i; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (fkeys->basic.ip_proto == IPPROTO_TCP) 10218c2ecf20Sopenharmony_ci fs->flow_type = TCP_V6_FLOW; 10228c2ecf20Sopenharmony_ci else if (fkeys->basic.ip_proto == IPPROTO_UDP) 10238c2ecf20Sopenharmony_ci fs->flow_type = UDP_V6_FLOW; 10248c2ecf20Sopenharmony_ci else 10258c2ecf20Sopenharmony_ci goto fltr_err; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = 10288c2ecf20Sopenharmony_ci fkeys->addrs.v6addrs.src; 10298c2ecf20Sopenharmony_ci *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = 10308c2ecf20Sopenharmony_ci fkeys->addrs.v6addrs.dst; 10318c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10328c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); 10338c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; 10368c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; 10398c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci fs->ring_cookie = fltr->rxq; 10438c2ecf20Sopenharmony_ci rc = 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cifltr_err: 10468c2ecf20Sopenharmony_ci rcu_read_unlock(); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return rc; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci#endif 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cistatic u64 get_ethtool_ipv4_rss(struct bnxt *bp) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) 10558c2ecf20Sopenharmony_ci return RXH_IP_SRC | RXH_IP_DST; 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic u64 get_ethtool_ipv6_rss(struct bnxt *bp) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) 10628c2ecf20Sopenharmony_ci return RXH_IP_SRC | RXH_IP_DST; 10638c2ecf20Sopenharmony_ci return 0; 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci cmd->data = 0; 10698c2ecf20Sopenharmony_ci switch (cmd->flow_type) { 10708c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 10718c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) 10728c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 10738c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 10748c2ecf20Sopenharmony_ci cmd->data |= get_ethtool_ipv4_rss(bp); 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 10778c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) 10788c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 10798c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 10808c2ecf20Sopenharmony_ci fallthrough; 10818c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 10828c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 10838c2ecf20Sopenharmony_ci case AH_V4_FLOW: 10848c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 10858c2ecf20Sopenharmony_ci case IPV4_FLOW: 10868c2ecf20Sopenharmony_ci cmd->data |= get_ethtool_ipv4_rss(bp); 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 10908c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) 10918c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 10928c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 10938c2ecf20Sopenharmony_ci cmd->data |= get_ethtool_ipv6_rss(bp); 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 10968c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) 10978c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST | 10988c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 10998c2ecf20Sopenharmony_ci fallthrough; 11008c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 11018c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 11028c2ecf20Sopenharmony_ci case AH_V6_FLOW: 11038c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 11048c2ecf20Sopenharmony_ci case IPV6_FLOW: 11058c2ecf20Sopenharmony_ci cmd->data |= get_ethtool_ipv6_rss(bp); 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 11128c2ecf20Sopenharmony_ci#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci u32 rss_hash_cfg = bp->rss_hash_cfg; 11178c2ecf20Sopenharmony_ci int tuple, rc = 0; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (cmd->data == RXH_4TUPLE) 11208c2ecf20Sopenharmony_ci tuple = 4; 11218c2ecf20Sopenharmony_ci else if (cmd->data == RXH_2TUPLE) 11228c2ecf20Sopenharmony_ci tuple = 2; 11238c2ecf20Sopenharmony_ci else if (!cmd->data) 11248c2ecf20Sopenharmony_ci tuple = 0; 11258c2ecf20Sopenharmony_ci else 11268c2ecf20Sopenharmony_ci return -EINVAL; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (cmd->flow_type == TCP_V4_FLOW) { 11298c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 11308c2ecf20Sopenharmony_ci if (tuple == 4) 11318c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 11328c2ecf20Sopenharmony_ci } else if (cmd->flow_type == UDP_V4_FLOW) { 11338c2ecf20Sopenharmony_ci if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 11348c2ecf20Sopenharmony_ci return -EINVAL; 11358c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 11368c2ecf20Sopenharmony_ci if (tuple == 4) 11378c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 11388c2ecf20Sopenharmony_ci } else if (cmd->flow_type == TCP_V6_FLOW) { 11398c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 11408c2ecf20Sopenharmony_ci if (tuple == 4) 11418c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 11428c2ecf20Sopenharmony_ci } else if (cmd->flow_type == UDP_V6_FLOW) { 11438c2ecf20Sopenharmony_ci if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 11448c2ecf20Sopenharmony_ci return -EINVAL; 11458c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 11468c2ecf20Sopenharmony_ci if (tuple == 4) 11478c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 11488c2ecf20Sopenharmony_ci } else if (tuple == 4) { 11498c2ecf20Sopenharmony_ci return -EINVAL; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci switch (cmd->flow_type) { 11538c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 11548c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 11558c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 11568c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 11578c2ecf20Sopenharmony_ci case AH_V4_FLOW: 11588c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 11598c2ecf20Sopenharmony_ci case IPV4_FLOW: 11608c2ecf20Sopenharmony_ci if (tuple == 2) 11618c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 11628c2ecf20Sopenharmony_ci else if (!tuple) 11638c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 11678c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 11688c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 11698c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 11708c2ecf20Sopenharmony_ci case AH_V6_FLOW: 11718c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 11728c2ecf20Sopenharmony_ci case IPV6_FLOW: 11738c2ecf20Sopenharmony_ci if (tuple == 2) 11748c2ecf20Sopenharmony_ci rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 11758c2ecf20Sopenharmony_ci else if (!tuple) 11768c2ecf20Sopenharmony_ci rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 11778c2ecf20Sopenharmony_ci break; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (bp->rss_hash_cfg == rss_hash_cfg) 11818c2ecf20Sopenharmony_ci return 0; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci bp->rss_hash_cfg = rss_hash_cfg; 11848c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 11858c2ecf20Sopenharmony_ci bnxt_close_nic(bp, false, false); 11868c2ecf20Sopenharmony_ci rc = bnxt_open_nic(bp, false, false); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci return rc; 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_cistatic int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 11928c2ecf20Sopenharmony_ci u32 *rule_locs) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 11958c2ecf20Sopenharmony_ci int rc = 0; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci switch (cmd->cmd) { 11988c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 11998c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 12008c2ecf20Sopenharmony_ci cmd->data = bp->rx_nr_rings; 12018c2ecf20Sopenharmony_ci break; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 12048c2ecf20Sopenharmony_ci cmd->rule_cnt = bp->ntp_fltr_count; 12058c2ecf20Sopenharmony_ci cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 12068c2ecf20Sopenharmony_ci break; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 12098c2ecf20Sopenharmony_ci rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 12138c2ecf20Sopenharmony_ci rc = bnxt_grxclsrule(bp, cmd); 12148c2ecf20Sopenharmony_ci break; 12158c2ecf20Sopenharmony_ci#endif 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 12188c2ecf20Sopenharmony_ci rc = bnxt_grxfh(bp, cmd); 12198c2ecf20Sopenharmony_ci break; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci default: 12228c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci return rc; 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_cistatic int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 12308c2ecf20Sopenharmony_ci{ 12318c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 12328c2ecf20Sopenharmony_ci int rc; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci switch (cmd->cmd) { 12358c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 12368c2ecf20Sopenharmony_ci rc = bnxt_srxfh(bp, cmd); 12378c2ecf20Sopenharmony_ci break; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci default: 12408c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 12418c2ecf20Sopenharmony_ci break; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci return rc; 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ciu32 bnxt_get_rxfh_indir_size(struct net_device *dev) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 12518c2ecf20Sopenharmony_ci return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 12528c2ecf20Sopenharmony_ci return HW_HASH_INDEX_SIZE; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic u32 bnxt_get_rxfh_key_size(struct net_device *dev) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci return HW_HASH_KEY_SIZE; 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 12618c2ecf20Sopenharmony_ci u8 *hfunc) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 12648c2ecf20Sopenharmony_ci struct bnxt_vnic_info *vnic; 12658c2ecf20Sopenharmony_ci u32 i, tbl_size; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (hfunc) 12688c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (!bp->vnic_info) 12718c2ecf20Sopenharmony_ci return 0; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci vnic = &bp->vnic_info[0]; 12748c2ecf20Sopenharmony_ci if (indir && bp->rss_indir_tbl) { 12758c2ecf20Sopenharmony_ci tbl_size = bnxt_get_rxfh_indir_size(dev); 12768c2ecf20Sopenharmony_ci for (i = 0; i < tbl_size; i++) 12778c2ecf20Sopenharmony_ci indir[i] = bp->rss_indir_tbl[i]; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (key && vnic->rss_hash_key) 12818c2ecf20Sopenharmony_ci memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci return 0; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 12878c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 12908c2ecf20Sopenharmony_ci int rc = 0; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (hfunc && hfunc != ETH_RSS_HASH_TOP) 12938c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (key) 12968c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (indir) { 12998c2ecf20Sopenharmony_ci u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci for (i = 0; i < tbl_size; i++) 13028c2ecf20Sopenharmony_ci bp->rss_indir_tbl[i] = indir[i]; 13038c2ecf20Sopenharmony_ci pad = bp->rss_indir_tbl_entries - tbl_size; 13048c2ecf20Sopenharmony_ci if (pad) 13058c2ecf20Sopenharmony_ci memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 13098c2ecf20Sopenharmony_ci bnxt_close_nic(bp, false, false); 13108c2ecf20Sopenharmony_ci rc = bnxt_open_nic(bp, false, false); 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci return rc; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic void bnxt_get_drvinfo(struct net_device *dev, 13168c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 13218c2ecf20Sopenharmony_ci strlcpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 13228c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 13238c2ecf20Sopenharmony_ci info->n_stats = bnxt_get_num_stats(bp); 13248c2ecf20Sopenharmony_ci info->testinfo_len = bp->num_tests; 13258c2ecf20Sopenharmony_ci /* TODO CHIMP_FW: eeprom dump details */ 13268c2ecf20Sopenharmony_ci info->eedump_len = 0; 13278c2ecf20Sopenharmony_ci /* TODO CHIMP FW: reg dump details */ 13288c2ecf20Sopenharmony_ci info->regdump_len = 0; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int bnxt_get_regs_len(struct net_device *dev) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 13348c2ecf20Sopenharmony_ci int reg_len; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (!BNXT_PF(bp)) 13378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci reg_len = BNXT_PXP_REG_LEN; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 13428c2ecf20Sopenharmony_ci reg_len += sizeof(struct pcie_ctx_hw_stats); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci return reg_len; 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 13488c2ecf20Sopenharmony_ci void *_p) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct pcie_ctx_hw_stats *hw_pcie_stats; 13518c2ecf20Sopenharmony_ci struct hwrm_pcie_qstats_input req = {0}; 13528c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 13538c2ecf20Sopenharmony_ci dma_addr_t hw_pcie_stats_addr; 13548c2ecf20Sopenharmony_ci int rc; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci regs->version = 0; 13578c2ecf20Sopenharmony_ci bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 13608c2ecf20Sopenharmony_ci return; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci hw_pcie_stats = dma_alloc_coherent(&bp->pdev->dev, 13638c2ecf20Sopenharmony_ci sizeof(*hw_pcie_stats), 13648c2ecf20Sopenharmony_ci &hw_pcie_stats_addr, GFP_KERNEL); 13658c2ecf20Sopenharmony_ci if (!hw_pcie_stats) 13668c2ecf20Sopenharmony_ci return; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci regs->version = 1; 13698c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PCIE_QSTATS, -1, -1); 13708c2ecf20Sopenharmony_ci req.pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 13718c2ecf20Sopenharmony_ci req.pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 13728c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 13738c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 13748c2ecf20Sopenharmony_ci if (!rc) { 13758c2ecf20Sopenharmony_ci __le64 *src = (__le64 *)hw_pcie_stats; 13768c2ecf20Sopenharmony_ci u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 13778c2ecf20Sopenharmony_ci int i; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 13808c2ecf20Sopenharmony_ci dst[i] = le64_to_cpu(src[i]); 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 13838c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, sizeof(*hw_pcie_stats), hw_pcie_stats, 13848c2ecf20Sopenharmony_ci hw_pcie_stats_addr); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci wol->supported = 0; 13928c2ecf20Sopenharmony_ci wol->wolopts = 0; 13938c2ecf20Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 13948c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_WOL_CAP) { 13958c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 13968c2ecf20Sopenharmony_ci if (bp->wol) 13978c2ecf20Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) 14068c2ecf20Sopenharmony_ci return -EINVAL; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 14098c2ecf20Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 14108c2ecf20Sopenharmony_ci return -EINVAL; 14118c2ecf20Sopenharmony_ci if (!bp->wol) { 14128c2ecf20Sopenharmony_ci if (bnxt_hwrm_alloc_wol_fltr(bp)) 14138c2ecf20Sopenharmony_ci return -EBUSY; 14148c2ecf20Sopenharmony_ci bp->wol = 1; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci } else { 14178c2ecf20Sopenharmony_ci if (bp->wol) { 14188c2ecf20Sopenharmony_ci if (bnxt_hwrm_free_wol_fltr(bp)) 14198c2ecf20Sopenharmony_ci return -EBUSY; 14208c2ecf20Sopenharmony_ci bp->wol = 0; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci return 0; 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ciu32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci u32 speed_mask = 0; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* TODO: support 25GB, 40GB, 50GB with different cable type */ 14318c2ecf20Sopenharmony_ci /* set the advertised speeds */ 14328c2ecf20Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 14338c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_100baseT_Full; 14348c2ecf20Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 14358c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_1000baseT_Full; 14368c2ecf20Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 14378c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_2500baseX_Full; 14388c2ecf20Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 14398c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_10000baseT_Full; 14408c2ecf20Sopenharmony_ci if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 14418c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_40000baseCR4_Full; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 14448c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_Pause; 14458c2ecf20Sopenharmony_ci else if (fw_pause & BNXT_LINK_PAUSE_TX) 14468c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_Asym_Pause; 14478c2ecf20Sopenharmony_ci else if (fw_pause & BNXT_LINK_PAUSE_RX) 14488c2ecf20Sopenharmony_ci speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci return speed_mask; 14518c2ecf20Sopenharmony_ci} 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 14548c2ecf20Sopenharmony_ci{ \ 14558c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 14568c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14578c2ecf20Sopenharmony_ci 100baseT_Full); \ 14588c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 14598c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14608c2ecf20Sopenharmony_ci 1000baseT_Full); \ 14618c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 14628c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14638c2ecf20Sopenharmony_ci 10000baseT_Full); \ 14648c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 14658c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14668c2ecf20Sopenharmony_ci 25000baseCR_Full); \ 14678c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 14688c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14698c2ecf20Sopenharmony_ci 40000baseCR4_Full);\ 14708c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 14718c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14728c2ecf20Sopenharmony_ci 50000baseCR2_Full);\ 14738c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 14748c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14758c2ecf20Sopenharmony_ci 100000baseCR4_Full);\ 14768c2ecf20Sopenharmony_ci if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 14778c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14788c2ecf20Sopenharmony_ci Pause); \ 14798c2ecf20Sopenharmony_ci if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 14808c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode( \ 14818c2ecf20Sopenharmony_ci lk_ksettings, name, Asym_Pause);\ 14828c2ecf20Sopenharmony_ci } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 14838c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 14848c2ecf20Sopenharmony_ci Asym_Pause); \ 14858c2ecf20Sopenharmony_ci } \ 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 14898c2ecf20Sopenharmony_ci{ \ 14908c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 14918c2ecf20Sopenharmony_ci 100baseT_Full) || \ 14928c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 14938c2ecf20Sopenharmony_ci 100baseT_Half)) \ 14948c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 14958c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 14968c2ecf20Sopenharmony_ci 1000baseT_Full) || \ 14978c2ecf20Sopenharmony_ci ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 14988c2ecf20Sopenharmony_ci 1000baseT_Half)) \ 14998c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 15008c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15018c2ecf20Sopenharmony_ci 10000baseT_Full)) \ 15028c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 15038c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15048c2ecf20Sopenharmony_ci 25000baseCR_Full)) \ 15058c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 15068c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15078c2ecf20Sopenharmony_ci 40000baseCR4_Full)) \ 15088c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 15098c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15108c2ecf20Sopenharmony_ci 50000baseCR2_Full)) \ 15118c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 15128c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15138c2ecf20Sopenharmony_ci 100000baseCR4_Full)) \ 15148c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 15188c2ecf20Sopenharmony_ci{ \ 15198c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 15208c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 15218c2ecf20Sopenharmony_ci 50000baseCR_Full); \ 15228c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 15238c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 15248c2ecf20Sopenharmony_ci 100000baseCR2_Full);\ 15258c2ecf20Sopenharmony_ci if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 15268c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 15278c2ecf20Sopenharmony_ci 200000baseCR4_Full);\ 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 15318c2ecf20Sopenharmony_ci{ \ 15328c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15338c2ecf20Sopenharmony_ci 50000baseCR_Full)) \ 15348c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 15358c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15368c2ecf20Sopenharmony_ci 100000baseCR2_Full)) \ 15378c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 15388c2ecf20Sopenharmony_ci if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 15398c2ecf20Sopenharmony_ci 200000baseCR4_Full)) \ 15408c2ecf20Sopenharmony_ci (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 15448c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci u16 fec_cfg = link_info->fec_cfg; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 15498c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 15508c2ecf20Sopenharmony_ci lk_ksettings->link_modes.advertising); 15518c2ecf20Sopenharmony_ci return; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R) 15548c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 15558c2ecf20Sopenharmony_ci lk_ksettings->link_modes.advertising); 15568c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS) 15578c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 15588c2ecf20Sopenharmony_ci lk_ksettings->link_modes.advertising); 15598c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS) 15608c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 15618c2ecf20Sopenharmony_ci lk_ksettings->link_modes.advertising); 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 15658c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci u16 fw_speeds = link_info->advertising; 15688c2ecf20Sopenharmony_ci u8 fw_pause = 0; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 15718c2ecf20Sopenharmony_ci fw_pause = link_info->auto_pause_setting; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 15748c2ecf20Sopenharmony_ci fw_speeds = link_info->advertising_pam4; 15758c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 15768c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 15808c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 15818c2ecf20Sopenharmony_ci{ 15828c2ecf20Sopenharmony_ci u16 fw_speeds = link_info->lp_auto_link_speeds; 15838c2ecf20Sopenharmony_ci u8 fw_pause = 0; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 15868c2ecf20Sopenharmony_ci fw_pause = link_info->lp_pause; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 15898c2ecf20Sopenharmony_ci lp_advertising); 15908c2ecf20Sopenharmony_ci fw_speeds = link_info->lp_auto_pam4_link_speeds; 15918c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 15958c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci u16 fec_cfg = link_info->fec_cfg; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) { 16008c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16018c2ecf20Sopenharmony_ci lk_ksettings->link_modes.supported); 16028c2ecf20Sopenharmony_ci return; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 16058c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16068c2ecf20Sopenharmony_ci lk_ksettings->link_modes.supported); 16078c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 16088c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16098c2ecf20Sopenharmony_ci lk_ksettings->link_modes.supported); 16108c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 16118c2ecf20Sopenharmony_ci linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16128c2ecf20Sopenharmony_ci lk_ksettings->link_modes.supported); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 16168c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci u16 fw_speeds = link_info->support_speeds; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 16218c2ecf20Sopenharmony_ci fw_speeds = link_info->support_pam4_speeds; 16228c2ecf20Sopenharmony_ci BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause); 16258c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 16268c2ecf20Sopenharmony_ci Asym_Pause); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (link_info->support_auto_speeds || 16298c2ecf20Sopenharmony_ci link_info->support_pam4_auto_speeds) 16308c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 16318c2ecf20Sopenharmony_ci Autoneg); 16328c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ciu32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci switch (fw_link_speed) { 16388c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_100MB: 16398c2ecf20Sopenharmony_ci return SPEED_100; 16408c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_1GB: 16418c2ecf20Sopenharmony_ci return SPEED_1000; 16428c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_2_5GB: 16438c2ecf20Sopenharmony_ci return SPEED_2500; 16448c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_10GB: 16458c2ecf20Sopenharmony_ci return SPEED_10000; 16468c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_20GB: 16478c2ecf20Sopenharmony_ci return SPEED_20000; 16488c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_25GB: 16498c2ecf20Sopenharmony_ci return SPEED_25000; 16508c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_40GB: 16518c2ecf20Sopenharmony_ci return SPEED_40000; 16528c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_50GB: 16538c2ecf20Sopenharmony_ci return SPEED_50000; 16548c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_100GB: 16558c2ecf20Sopenharmony_ci return SPEED_100000; 16568c2ecf20Sopenharmony_ci case BNXT_LINK_SPEED_200GB: 16578c2ecf20Sopenharmony_ci return SPEED_200000; 16588c2ecf20Sopenharmony_ci default: 16598c2ecf20Sopenharmony_ci return SPEED_UNKNOWN; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic int bnxt_get_link_ksettings(struct net_device *dev, 16648c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *lk_ksettings) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 16678c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 16688c2ecf20Sopenharmony_ci struct ethtool_link_settings *base = &lk_ksettings->base; 16698c2ecf20Sopenharmony_ci u32 ethtool_speed; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 16728c2ecf20Sopenharmony_ci mutex_lock(&bp->link_lock); 16738c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 16768c2ecf20Sopenharmony_ci if (link_info->autoneg) { 16778c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 16788c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, 16798c2ecf20Sopenharmony_ci advertising, Autoneg); 16808c2ecf20Sopenharmony_ci base->autoneg = AUTONEG_ENABLE; 16818c2ecf20Sopenharmony_ci base->duplex = DUPLEX_UNKNOWN; 16828c2ecf20Sopenharmony_ci if (link_info->phy_link_status == BNXT_LINK_LINK) { 16838c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 16848c2ecf20Sopenharmony_ci if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 16858c2ecf20Sopenharmony_ci base->duplex = DUPLEX_FULL; 16868c2ecf20Sopenharmony_ci else 16878c2ecf20Sopenharmony_ci base->duplex = DUPLEX_HALF; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 16908c2ecf20Sopenharmony_ci } else { 16918c2ecf20Sopenharmony_ci base->autoneg = AUTONEG_DISABLE; 16928c2ecf20Sopenharmony_ci ethtool_speed = 16938c2ecf20Sopenharmony_ci bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 16948c2ecf20Sopenharmony_ci base->duplex = DUPLEX_HALF; 16958c2ecf20Sopenharmony_ci if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 16968c2ecf20Sopenharmony_ci base->duplex = DUPLEX_FULL; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci base->speed = ethtool_speed; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci base->port = PORT_NONE; 17018c2ecf20Sopenharmony_ci if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 17028c2ecf20Sopenharmony_ci base->port = PORT_TP; 17038c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 17048c2ecf20Sopenharmony_ci TP); 17058c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 17068c2ecf20Sopenharmony_ci TP); 17078c2ecf20Sopenharmony_ci } else { 17088c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 17098c2ecf20Sopenharmony_ci FIBRE); 17108c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 17118c2ecf20Sopenharmony_ci FIBRE); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 17148c2ecf20Sopenharmony_ci base->port = PORT_DA; 17158c2ecf20Sopenharmony_ci else if (link_info->media_type == 17168c2ecf20Sopenharmony_ci PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 17178c2ecf20Sopenharmony_ci base->port = PORT_FIBRE; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci base->phy_address = link_info->phy_addr; 17208c2ecf20Sopenharmony_ci mutex_unlock(&bp->link_lock); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci return 0; 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cistatic int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 17288c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 17298c2ecf20Sopenharmony_ci u16 support_pam4_spds = link_info->support_pam4_speeds; 17308c2ecf20Sopenharmony_ci u16 support_spds = link_info->support_speeds; 17318c2ecf20Sopenharmony_ci u8 sig_mode = BNXT_SIG_MODE_NRZ; 17328c2ecf20Sopenharmony_ci u16 fw_speed = 0; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci switch (ethtool_speed) { 17358c2ecf20Sopenharmony_ci case SPEED_100: 17368c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 17378c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17388c2ecf20Sopenharmony_ci break; 17398c2ecf20Sopenharmony_ci case SPEED_1000: 17408c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 17418c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci case SPEED_2500: 17448c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 17458c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci case SPEED_10000: 17488c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 17498c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci case SPEED_20000: 17528c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 17538c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case SPEED_25000: 17568c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 17578c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 17588c2ecf20Sopenharmony_ci break; 17598c2ecf20Sopenharmony_ci case SPEED_40000: 17608c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 17618c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci case SPEED_50000: 17648c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 17658c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 17668c2ecf20Sopenharmony_ci } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 17678c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 17688c2ecf20Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci case SPEED_100000: 17728c2ecf20Sopenharmony_ci if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 17738c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 17748c2ecf20Sopenharmony_ci } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 17758c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 17768c2ecf20Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci break; 17798c2ecf20Sopenharmony_ci case SPEED_200000: 17808c2ecf20Sopenharmony_ci if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 17818c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 17828c2ecf20Sopenharmony_ci sig_mode = BNXT_SIG_MODE_PAM4; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci break; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (!fw_speed) { 17888c2ecf20Sopenharmony_ci netdev_err(dev, "unsupported speed!\n"); 17898c2ecf20Sopenharmony_ci return -EINVAL; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci if (link_info->req_link_speed == fw_speed && 17938c2ecf20Sopenharmony_ci link_info->req_signal_mode == sig_mode && 17948c2ecf20Sopenharmony_ci link_info->autoneg == 0) 17958c2ecf20Sopenharmony_ci return -EALREADY; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci link_info->req_link_speed = fw_speed; 17988c2ecf20Sopenharmony_ci link_info->req_signal_mode = sig_mode; 17998c2ecf20Sopenharmony_ci link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 18008c2ecf20Sopenharmony_ci link_info->autoneg = 0; 18018c2ecf20Sopenharmony_ci link_info->advertising = 0; 18028c2ecf20Sopenharmony_ci link_info->advertising_pam4 = 0; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci return 0; 18058c2ecf20Sopenharmony_ci} 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ciu16 bnxt_get_fw_auto_link_speeds(u32 advertising) 18088c2ecf20Sopenharmony_ci{ 18098c2ecf20Sopenharmony_ci u16 fw_speed_mask = 0; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* only support autoneg at speed 100, 1000, and 10000 */ 18128c2ecf20Sopenharmony_ci if (advertising & (ADVERTISED_100baseT_Full | 18138c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Half)) { 18148c2ecf20Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci if (advertising & (ADVERTISED_1000baseT_Full | 18178c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Half)) { 18188c2ecf20Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_10000baseT_Full) 18218c2ecf20Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_40000baseCR4_Full) 18248c2ecf20Sopenharmony_ci fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci return fw_speed_mask; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic int bnxt_set_link_ksettings(struct net_device *dev, 18308c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *lk_ksettings) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 18338c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 18348c2ecf20Sopenharmony_ci const struct ethtool_link_settings *base = &lk_ksettings->base; 18358c2ecf20Sopenharmony_ci bool set_pause = false; 18368c2ecf20Sopenharmony_ci u32 speed; 18378c2ecf20Sopenharmony_ci int rc = 0; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 18408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci mutex_lock(&bp->link_lock); 18438c2ecf20Sopenharmony_ci if (base->autoneg == AUTONEG_ENABLE) { 18448c2ecf20Sopenharmony_ci link_info->advertising = 0; 18458c2ecf20Sopenharmony_ci link_info->advertising_pam4 = 0; 18468c2ecf20Sopenharmony_ci BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 18478c2ecf20Sopenharmony_ci advertising); 18488c2ecf20Sopenharmony_ci BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 18498c2ecf20Sopenharmony_ci lk_ksettings, advertising); 18508c2ecf20Sopenharmony_ci link_info->autoneg |= BNXT_AUTONEG_SPEED; 18518c2ecf20Sopenharmony_ci if (!link_info->advertising && !link_info->advertising_pam4) { 18528c2ecf20Sopenharmony_ci link_info->advertising = link_info->support_auto_speeds; 18538c2ecf20Sopenharmony_ci link_info->advertising_pam4 = 18548c2ecf20Sopenharmony_ci link_info->support_pam4_auto_speeds; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci /* any change to autoneg will cause link change, therefore the 18578c2ecf20Sopenharmony_ci * driver should put back the original pause setting in autoneg 18588c2ecf20Sopenharmony_ci */ 18598c2ecf20Sopenharmony_ci set_pause = true; 18608c2ecf20Sopenharmony_ci } else { 18618c2ecf20Sopenharmony_ci u8 phy_type = link_info->phy_type; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 18648c2ecf20Sopenharmony_ci phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 18658c2ecf20Sopenharmony_ci link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 18668c2ecf20Sopenharmony_ci netdev_err(dev, "10GBase-T devices must autoneg\n"); 18678c2ecf20Sopenharmony_ci rc = -EINVAL; 18688c2ecf20Sopenharmony_ci goto set_setting_exit; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci if (base->duplex == DUPLEX_HALF) { 18718c2ecf20Sopenharmony_ci netdev_err(dev, "HALF DUPLEX is not supported!\n"); 18728c2ecf20Sopenharmony_ci rc = -EINVAL; 18738c2ecf20Sopenharmony_ci goto set_setting_exit; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci speed = base->speed; 18768c2ecf20Sopenharmony_ci rc = bnxt_force_link_speed(dev, speed); 18778c2ecf20Sopenharmony_ci if (rc) { 18788c2ecf20Sopenharmony_ci if (rc == -EALREADY) 18798c2ecf20Sopenharmony_ci rc = 0; 18808c2ecf20Sopenharmony_ci goto set_setting_exit; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (netif_running(dev)) 18858c2ecf20Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ciset_setting_exit: 18888c2ecf20Sopenharmony_ci mutex_unlock(&bp->link_lock); 18898c2ecf20Sopenharmony_ci return rc; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic int bnxt_get_fecparam(struct net_device *dev, 18938c2ecf20Sopenharmony_ci struct ethtool_fecparam *fec) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 18968c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info; 18978c2ecf20Sopenharmony_ci u8 active_fec; 18988c2ecf20Sopenharmony_ci u16 fec_cfg; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci link_info = &bp->link_info; 19018c2ecf20Sopenharmony_ci fec_cfg = link_info->fec_cfg; 19028c2ecf20Sopenharmony_ci active_fec = link_info->active_fec_sig_mode & 19038c2ecf20Sopenharmony_ci PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19048c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) { 19058c2ecf20Sopenharmony_ci fec->fec = ETHTOOL_FEC_NONE; 19068c2ecf20Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_NONE; 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_AUTONEG) 19108c2ecf20Sopenharmony_ci fec->fec |= ETHTOOL_FEC_AUTO; 19118c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19128c2ecf20Sopenharmony_ci fec->fec |= ETHTOOL_FEC_BASER; 19138c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_RS) 19148c2ecf20Sopenharmony_ci fec->fec |= ETHTOOL_FEC_RS; 19158c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_ENC_LLRS) 19168c2ecf20Sopenharmony_ci fec->fec |= ETHTOOL_FEC_LLRS; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci switch (active_fec) { 19198c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19208c2ecf20Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_BASER; 19218c2ecf20Sopenharmony_ci break; 19228c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19238c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19248c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19258c2ecf20Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_RS; 19268c2ecf20Sopenharmony_ci break; 19278c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19288c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19298c2ecf20Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_LLRS; 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 19328c2ecf20Sopenharmony_ci fec->active_fec |= ETHTOOL_FEC_OFF; 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci return 0; 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 19398c2ecf20Sopenharmony_ci u32 fec) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (fec & ETHTOOL_FEC_BASER) 19448c2ecf20Sopenharmony_ci fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 19458c2ecf20Sopenharmony_ci else if (fec & ETHTOOL_FEC_RS) 19468c2ecf20Sopenharmony_ci fw_fec |= BNXT_FEC_RS_ON(link_info); 19478c2ecf20Sopenharmony_ci else if (fec & ETHTOOL_FEC_LLRS) 19488c2ecf20Sopenharmony_ci fw_fec |= BNXT_FEC_LLRS_ON; 19498c2ecf20Sopenharmony_ci return fw_fec; 19508c2ecf20Sopenharmony_ci} 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_cistatic int bnxt_set_fecparam(struct net_device *dev, 19538c2ecf20Sopenharmony_ci struct ethtool_fecparam *fecparam) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci struct hwrm_port_phy_cfg_input req = {0}; 19568c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 19578c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info; 19588c2ecf20Sopenharmony_ci u32 new_cfg, fec = fecparam->fec; 19598c2ecf20Sopenharmony_ci u16 fec_cfg; 19608c2ecf20Sopenharmony_ci int rc; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci link_info = &bp->link_info; 19638c2ecf20Sopenharmony_ci fec_cfg = link_info->fec_cfg; 19648c2ecf20Sopenharmony_ci if (fec_cfg & BNXT_FEC_NONE) 19658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (fec & ETHTOOL_FEC_OFF) { 19688c2ecf20Sopenharmony_ci new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 19698c2ecf20Sopenharmony_ci BNXT_FEC_ALL_OFF(link_info); 19708c2ecf20Sopenharmony_ci goto apply_fec; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 19738c2ecf20Sopenharmony_ci ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 19748c2ecf20Sopenharmony_ci ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 19758c2ecf20Sopenharmony_ci ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 19768c2ecf20Sopenharmony_ci return -EINVAL; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (fec & ETHTOOL_FEC_AUTO) { 19798c2ecf20Sopenharmony_ci if (!link_info->autoneg) 19808c2ecf20Sopenharmony_ci return -EINVAL; 19818c2ecf20Sopenharmony_ci new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 19828c2ecf20Sopenharmony_ci } else { 19838c2ecf20Sopenharmony_ci new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ciapply_fec: 19878c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1); 19888c2ecf20Sopenharmony_ci req.flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 19898c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 19908c2ecf20Sopenharmony_ci /* update current settings */ 19918c2ecf20Sopenharmony_ci if (!rc) { 19928c2ecf20Sopenharmony_ci mutex_lock(&bp->link_lock); 19938c2ecf20Sopenharmony_ci bnxt_update_link(bp, false); 19948c2ecf20Sopenharmony_ci mutex_unlock(&bp->link_lock); 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci return rc; 19978c2ecf20Sopenharmony_ci} 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_cistatic void bnxt_get_pauseparam(struct net_device *dev, 20008c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 20038c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (BNXT_VF(bp)) 20068c2ecf20Sopenharmony_ci return; 20078c2ecf20Sopenharmony_ci epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20088c2ecf20Sopenharmony_ci epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20098c2ecf20Sopenharmony_ci epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 20108c2ecf20Sopenharmony_ci} 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_cistatic void bnxt_get_pause_stats(struct net_device *dev, 20138c2ecf20Sopenharmony_ci struct ethtool_pause_stats *epstat) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 20168c2ecf20Sopenharmony_ci u64 *rx, *tx; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 20198c2ecf20Sopenharmony_ci return; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci rx = bp->port_stats.sw_stats; 20228c2ecf20Sopenharmony_ci tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 20258c2ecf20Sopenharmony_ci epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 20268c2ecf20Sopenharmony_ci} 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic int bnxt_set_pauseparam(struct net_device *dev, 20298c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 20308c2ecf20Sopenharmony_ci{ 20318c2ecf20Sopenharmony_ci int rc = 0; 20328c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 20338c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 20368c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci mutex_lock(&bp->link_lock); 20398c2ecf20Sopenharmony_ci if (epause->autoneg) { 20408c2ecf20Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 20418c2ecf20Sopenharmony_ci rc = -EINVAL; 20428c2ecf20Sopenharmony_ci goto pause_exit; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 20468c2ecf20Sopenharmony_ci link_info->req_flow_ctrl = 0; 20478c2ecf20Sopenharmony_ci } else { 20488c2ecf20Sopenharmony_ci /* when transition from auto pause to force pause, 20498c2ecf20Sopenharmony_ci * force a link change 20508c2ecf20Sopenharmony_ci */ 20518c2ecf20Sopenharmony_ci if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 20528c2ecf20Sopenharmony_ci link_info->force_link_chng = true; 20538c2ecf20Sopenharmony_ci link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 20548c2ecf20Sopenharmony_ci link_info->req_flow_ctrl = 0; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci if (epause->rx_pause) 20578c2ecf20Sopenharmony_ci link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (epause->tx_pause) 20608c2ecf20Sopenharmony_ci link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (netif_running(dev)) 20638c2ecf20Sopenharmony_ci rc = bnxt_hwrm_set_pause(bp); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_cipause_exit: 20668c2ecf20Sopenharmony_ci mutex_unlock(&bp->link_lock); 20678c2ecf20Sopenharmony_ci return rc; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_cistatic u32 bnxt_get_link(struct net_device *dev) 20718c2ecf20Sopenharmony_ci{ 20728c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci /* TODO: handle MF, VF, driver close case */ 20758c2ecf20Sopenharmony_ci return bp->link_info.link_up; 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ciint bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 20798c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 20808c2ecf20Sopenharmony_ci{ 20818c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dev_info_output *resp = bp->hwrm_cmd_resp_addr; 20828c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dev_info_input req = {0}; 20838c2ecf20Sopenharmony_ci int rc; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci if (BNXT_VF(bp)) 20868c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DEV_INFO, -1, -1); 20898c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 20908c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 20918c2ecf20Sopenharmony_ci if (!rc) 20928c2ecf20Sopenharmony_ci memcpy(nvm_dev_info, resp, sizeof(*resp)); 20938c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 20948c2ecf20Sopenharmony_ci return rc; 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_cistatic void bnxt_print_admin_err(struct bnxt *bp) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 21008c2ecf20Sopenharmony_ci} 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_cistatic int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21038c2ecf20Sopenharmony_ci u16 ext, u16 *index, u32 *item_length, 21048c2ecf20Sopenharmony_ci u32 *data_length); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic int bnxt_flash_nvram(struct net_device *dev, 21078c2ecf20Sopenharmony_ci u16 dir_type, 21088c2ecf20Sopenharmony_ci u16 dir_ordinal, 21098c2ecf20Sopenharmony_ci u16 dir_ext, 21108c2ecf20Sopenharmony_ci u16 dir_attr, 21118c2ecf20Sopenharmony_ci const u8 *data, 21128c2ecf20Sopenharmony_ci size_t data_len) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 21158c2ecf20Sopenharmony_ci int rc; 21168c2ecf20Sopenharmony_ci struct hwrm_nvm_write_input req = {0}; 21178c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 21188c2ecf20Sopenharmony_ci u8 *kmem; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci req.dir_type = cpu_to_le16(dir_type); 21238c2ecf20Sopenharmony_ci req.dir_ordinal = cpu_to_le16(dir_ordinal); 21248c2ecf20Sopenharmony_ci req.dir_ext = cpu_to_le16(dir_ext); 21258c2ecf20Sopenharmony_ci req.dir_attr = cpu_to_le16(dir_attr); 21268c2ecf20Sopenharmony_ci req.dir_data_length = cpu_to_le32(data_len); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle, 21298c2ecf20Sopenharmony_ci GFP_KERNEL); 21308c2ecf20Sopenharmony_ci if (!kmem) { 21318c2ecf20Sopenharmony_ci netdev_err(dev, "dma_alloc_coherent failure, length = %u\n", 21328c2ecf20Sopenharmony_ci (unsigned)data_len); 21338c2ecf20Sopenharmony_ci return -ENOMEM; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci memcpy(kmem, data, data_len); 21368c2ecf20Sopenharmony_ci req.host_src_addr = cpu_to_le64(dma_handle); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT); 21398c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (rc == -EACCES) 21428c2ecf20Sopenharmony_ci bnxt_print_admin_err(bp); 21438c2ecf20Sopenharmony_ci return rc; 21448c2ecf20Sopenharmony_ci} 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_cistatic int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 21478c2ecf20Sopenharmony_ci u8 self_reset, u8 flags) 21488c2ecf20Sopenharmony_ci{ 21498c2ecf20Sopenharmony_ci struct hwrm_fw_reset_input req = {0}; 21508c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 21518c2ecf20Sopenharmony_ci int rc; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FW_RESET, -1, -1); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci req.embedded_proc_type = proc_type; 21568c2ecf20Sopenharmony_ci req.selfrst_status = self_reset; 21578c2ecf20Sopenharmony_ci req.flags = flags; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 21608c2ecf20Sopenharmony_ci rc = hwrm_send_message_silent(bp, &req, sizeof(req), 21618c2ecf20Sopenharmony_ci HWRM_CMD_TIMEOUT); 21628c2ecf20Sopenharmony_ci } else { 21638c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 21648c2ecf20Sopenharmony_ci if (rc == -EACCES) 21658c2ecf20Sopenharmony_ci bnxt_print_admin_err(bp); 21668c2ecf20Sopenharmony_ci } 21678c2ecf20Sopenharmony_ci return rc; 21688c2ecf20Sopenharmony_ci} 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset(struct net_device *dev, 21718c2ecf20Sopenharmony_ci enum bnxt_nvm_directory_type dir_type) 21728c2ecf20Sopenharmony_ci{ 21738c2ecf20Sopenharmony_ci u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 21748c2ecf20Sopenharmony_ci u8 proc_type, flags = 0; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 21778c2ecf20Sopenharmony_ci /* (e.g. when firmware isn't already running) */ 21788c2ecf20Sopenharmony_ci switch (dir_type) { 21798c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 21808c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 21818c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 21828c2ecf20Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 21838c2ecf20Sopenharmony_ci /* Self-reset ChiMP upon next PCIe reset: */ 21848c2ecf20Sopenharmony_ci self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 21858c2ecf20Sopenharmony_ci break; 21868c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 21878c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 21888c2ecf20Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 21898c2ecf20Sopenharmony_ci /* Self-reset APE upon next PCIe reset: */ 21908c2ecf20Sopenharmony_ci self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 21918c2ecf20Sopenharmony_ci break; 21928c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 21938c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 21948c2ecf20Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 21958c2ecf20Sopenharmony_ci break; 21968c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 21978c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 21988c2ecf20Sopenharmony_ci proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 21998c2ecf20Sopenharmony_ci break; 22008c2ecf20Sopenharmony_ci default: 22018c2ecf20Sopenharmony_ci return -EINVAL; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 22058c2ecf20Sopenharmony_ci} 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset_chip(struct net_device *dev) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 22108c2ecf20Sopenharmony_ci u8 flags = 0; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 22138c2ecf20Sopenharmony_ci flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, 22168c2ecf20Sopenharmony_ci FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 22178c2ecf20Sopenharmony_ci FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 22188c2ecf20Sopenharmony_ci flags); 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset_ap(struct net_device *dev) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 22248c2ecf20Sopenharmony_ci FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 22258c2ecf20Sopenharmony_ci 0); 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cistatic int bnxt_flash_firmware(struct net_device *dev, 22298c2ecf20Sopenharmony_ci u16 dir_type, 22308c2ecf20Sopenharmony_ci const u8 *fw_data, 22318c2ecf20Sopenharmony_ci size_t fw_size) 22328c2ecf20Sopenharmony_ci{ 22338c2ecf20Sopenharmony_ci int rc = 0; 22348c2ecf20Sopenharmony_ci u16 code_type; 22358c2ecf20Sopenharmony_ci u32 stored_crc; 22368c2ecf20Sopenharmony_ci u32 calculated_crc; 22378c2ecf20Sopenharmony_ci struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci switch (dir_type) { 22408c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 22418c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 22428c2ecf20Sopenharmony_ci code_type = CODE_BOOT; 22438c2ecf20Sopenharmony_ci break; 22448c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 22458c2ecf20Sopenharmony_ci code_type = CODE_CHIMP_PATCH; 22468c2ecf20Sopenharmony_ci break; 22478c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 22488c2ecf20Sopenharmony_ci code_type = CODE_MCTP_PASSTHRU; 22498c2ecf20Sopenharmony_ci break; 22508c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 22518c2ecf20Sopenharmony_ci code_type = CODE_APE_PATCH; 22528c2ecf20Sopenharmony_ci break; 22538c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 22548c2ecf20Sopenharmony_ci code_type = CODE_KONG_FW; 22558c2ecf20Sopenharmony_ci break; 22568c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 22578c2ecf20Sopenharmony_ci code_type = CODE_KONG_PATCH; 22588c2ecf20Sopenharmony_ci break; 22598c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 22608c2ecf20Sopenharmony_ci code_type = CODE_BONO_FW; 22618c2ecf20Sopenharmony_ci break; 22628c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 22638c2ecf20Sopenharmony_ci code_type = CODE_BONO_PATCH; 22648c2ecf20Sopenharmony_ci break; 22658c2ecf20Sopenharmony_ci default: 22668c2ecf20Sopenharmony_ci netdev_err(dev, "Unsupported directory entry type: %u\n", 22678c2ecf20Sopenharmony_ci dir_type); 22688c2ecf20Sopenharmony_ci return -EINVAL; 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci if (fw_size < sizeof(struct bnxt_fw_header)) { 22718c2ecf20Sopenharmony_ci netdev_err(dev, "Invalid firmware file size: %u\n", 22728c2ecf20Sopenharmony_ci (unsigned int)fw_size); 22738c2ecf20Sopenharmony_ci return -EINVAL; 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 22768c2ecf20Sopenharmony_ci netdev_err(dev, "Invalid firmware signature: %08X\n", 22778c2ecf20Sopenharmony_ci le32_to_cpu(header->signature)); 22788c2ecf20Sopenharmony_ci return -EINVAL; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci if (header->code_type != code_type) { 22818c2ecf20Sopenharmony_ci netdev_err(dev, "Expected firmware type: %d, read: %d\n", 22828c2ecf20Sopenharmony_ci code_type, header->code_type); 22838c2ecf20Sopenharmony_ci return -EINVAL; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci if (header->device != DEVICE_CUMULUS_FAMILY) { 22868c2ecf20Sopenharmony_ci netdev_err(dev, "Expected firmware device family %d, read: %d\n", 22878c2ecf20Sopenharmony_ci DEVICE_CUMULUS_FAMILY, header->device); 22888c2ecf20Sopenharmony_ci return -EINVAL; 22898c2ecf20Sopenharmony_ci } 22908c2ecf20Sopenharmony_ci /* Confirm the CRC32 checksum of the file: */ 22918c2ecf20Sopenharmony_ci stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 22928c2ecf20Sopenharmony_ci sizeof(stored_crc))); 22938c2ecf20Sopenharmony_ci calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 22948c2ecf20Sopenharmony_ci if (calculated_crc != stored_crc) { 22958c2ecf20Sopenharmony_ci netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 22968c2ecf20Sopenharmony_ci (unsigned long)stored_crc, 22978c2ecf20Sopenharmony_ci (unsigned long)calculated_crc); 22988c2ecf20Sopenharmony_ci return -EINVAL; 22998c2ecf20Sopenharmony_ci } 23008c2ecf20Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 23018c2ecf20Sopenharmony_ci 0, 0, fw_data, fw_size); 23028c2ecf20Sopenharmony_ci if (rc == 0) /* Firmware update successful */ 23038c2ecf20Sopenharmony_ci rc = bnxt_firmware_reset(dev, dir_type); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci return rc; 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_cistatic int bnxt_flash_microcode(struct net_device *dev, 23098c2ecf20Sopenharmony_ci u16 dir_type, 23108c2ecf20Sopenharmony_ci const u8 *fw_data, 23118c2ecf20Sopenharmony_ci size_t fw_size) 23128c2ecf20Sopenharmony_ci{ 23138c2ecf20Sopenharmony_ci struct bnxt_ucode_trailer *trailer; 23148c2ecf20Sopenharmony_ci u32 calculated_crc; 23158c2ecf20Sopenharmony_ci u32 stored_crc; 23168c2ecf20Sopenharmony_ci int rc = 0; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 23198c2ecf20Sopenharmony_ci netdev_err(dev, "Invalid microcode file size: %u\n", 23208c2ecf20Sopenharmony_ci (unsigned int)fw_size); 23218c2ecf20Sopenharmony_ci return -EINVAL; 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 23248c2ecf20Sopenharmony_ci sizeof(*trailer))); 23258c2ecf20Sopenharmony_ci if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 23268c2ecf20Sopenharmony_ci netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 23278c2ecf20Sopenharmony_ci le32_to_cpu(trailer->sig)); 23288c2ecf20Sopenharmony_ci return -EINVAL; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci if (le16_to_cpu(trailer->dir_type) != dir_type) { 23318c2ecf20Sopenharmony_ci netdev_err(dev, "Expected microcode type: %d, read: %d\n", 23328c2ecf20Sopenharmony_ci dir_type, le16_to_cpu(trailer->dir_type)); 23338c2ecf20Sopenharmony_ci return -EINVAL; 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci if (le16_to_cpu(trailer->trailer_length) < 23368c2ecf20Sopenharmony_ci sizeof(struct bnxt_ucode_trailer)) { 23378c2ecf20Sopenharmony_ci netdev_err(dev, "Invalid microcode trailer length: %d\n", 23388c2ecf20Sopenharmony_ci le16_to_cpu(trailer->trailer_length)); 23398c2ecf20Sopenharmony_ci return -EINVAL; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci /* Confirm the CRC32 checksum of the file: */ 23438c2ecf20Sopenharmony_ci stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 23448c2ecf20Sopenharmony_ci sizeof(stored_crc))); 23458c2ecf20Sopenharmony_ci calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 23468c2ecf20Sopenharmony_ci if (calculated_crc != stored_crc) { 23478c2ecf20Sopenharmony_ci netdev_err(dev, 23488c2ecf20Sopenharmony_ci "CRC32 (%08lX) does not match calculated: %08lX\n", 23498c2ecf20Sopenharmony_ci (unsigned long)stored_crc, 23508c2ecf20Sopenharmony_ci (unsigned long)calculated_crc); 23518c2ecf20Sopenharmony_ci return -EINVAL; 23528c2ecf20Sopenharmony_ci } 23538c2ecf20Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 23548c2ecf20Sopenharmony_ci 0, 0, fw_data, fw_size); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci return rc; 23578c2ecf20Sopenharmony_ci} 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 23608c2ecf20Sopenharmony_ci{ 23618c2ecf20Sopenharmony_ci switch (dir_type) { 23628c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_CHIMP_PATCH: 23638c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE: 23648c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BOOTCODE_2: 23658c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_FW: 23668c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_APE_PATCH: 23678c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_FW: 23688c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_KONG_PATCH: 23698c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_FW: 23708c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_BONO_PATCH: 23718c2ecf20Sopenharmony_ci return true; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci return false; 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci switch (dir_type) { 23808c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_AVS: 23818c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_EXP_ROM_MBA: 23828c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_PCIE: 23838c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_TSCF_UCODE: 23848c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_EXT_PHY: 23858c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_CCM: 23868c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT: 23878c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 23888c2ecf20Sopenharmony_ci case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 23898c2ecf20Sopenharmony_ci return true; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci return false; 23938c2ecf20Sopenharmony_ci} 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_executable(u16 dir_type) 23968c2ecf20Sopenharmony_ci{ 23978c2ecf20Sopenharmony_ci return bnxt_dir_type_is_ape_bin_format(dir_type) || 23988c2ecf20Sopenharmony_ci bnxt_dir_type_is_other_exec_format(dir_type); 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cistatic int bnxt_flash_firmware_from_file(struct net_device *dev, 24028c2ecf20Sopenharmony_ci u16 dir_type, 24038c2ecf20Sopenharmony_ci const char *filename) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci const struct firmware *fw; 24068c2ecf20Sopenharmony_ci int rc; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci rc = request_firmware(&fw, filename, &dev->dev); 24098c2ecf20Sopenharmony_ci if (rc != 0) { 24108c2ecf20Sopenharmony_ci netdev_err(dev, "Error %d requesting firmware file: %s\n", 24118c2ecf20Sopenharmony_ci rc, filename); 24128c2ecf20Sopenharmony_ci return rc; 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci if (bnxt_dir_type_is_ape_bin_format(dir_type)) 24158c2ecf20Sopenharmony_ci rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 24168c2ecf20Sopenharmony_ci else if (bnxt_dir_type_is_other_exec_format(dir_type)) 24178c2ecf20Sopenharmony_ci rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 24188c2ecf20Sopenharmony_ci else 24198c2ecf20Sopenharmony_ci rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 24208c2ecf20Sopenharmony_ci 0, 0, fw->data, fw->size); 24218c2ecf20Sopenharmony_ci release_firmware(fw); 24228c2ecf20Sopenharmony_ci return rc; 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ciint bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 24268c2ecf20Sopenharmony_ci u32 install_type) 24278c2ecf20Sopenharmony_ci{ 24288c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 24298c2ecf20Sopenharmony_ci struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr; 24308c2ecf20Sopenharmony_ci struct hwrm_nvm_install_update_input install = {0}; 24318c2ecf20Sopenharmony_ci const struct firmware *fw; 24328c2ecf20Sopenharmony_ci u32 item_len; 24338c2ecf20Sopenharmony_ci int rc = 0; 24348c2ecf20Sopenharmony_ci u16 index; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci bnxt_hwrm_fw_set_time(bp); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 24398c2ecf20Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 24408c2ecf20Sopenharmony_ci &index, &item_len, NULL); 24418c2ecf20Sopenharmony_ci if (rc) { 24428c2ecf20Sopenharmony_ci netdev_err(dev, "PKG update area not created in nvram\n"); 24438c2ecf20Sopenharmony_ci return rc; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci rc = request_firmware(&fw, filename, &dev->dev); 24478c2ecf20Sopenharmony_ci if (rc != 0) { 24488c2ecf20Sopenharmony_ci netdev_err(dev, "PKG error %d requesting file: %s\n", 24498c2ecf20Sopenharmony_ci rc, filename); 24508c2ecf20Sopenharmony_ci return rc; 24518c2ecf20Sopenharmony_ci } 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci if (fw->size > item_len) { 24548c2ecf20Sopenharmony_ci netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", 24558c2ecf20Sopenharmony_ci (unsigned long)fw->size); 24568c2ecf20Sopenharmony_ci rc = -EFBIG; 24578c2ecf20Sopenharmony_ci } else { 24588c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 24598c2ecf20Sopenharmony_ci u8 *kmem; 24608c2ecf20Sopenharmony_ci struct hwrm_nvm_modify_input modify = {0}; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci modify.dir_idx = cpu_to_le16(index); 24658c2ecf20Sopenharmony_ci modify.len = cpu_to_le32(fw->size); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size, 24688c2ecf20Sopenharmony_ci &dma_handle, GFP_KERNEL); 24698c2ecf20Sopenharmony_ci if (!kmem) { 24708c2ecf20Sopenharmony_ci netdev_err(dev, 24718c2ecf20Sopenharmony_ci "dma_alloc_coherent failure, length = %u\n", 24728c2ecf20Sopenharmony_ci (unsigned int)fw->size); 24738c2ecf20Sopenharmony_ci rc = -ENOMEM; 24748c2ecf20Sopenharmony_ci } else { 24758c2ecf20Sopenharmony_ci memcpy(kmem, fw->data, fw->size); 24768c2ecf20Sopenharmony_ci modify.host_src_addr = cpu_to_le64(dma_handle); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &modify, sizeof(modify), 24798c2ecf20Sopenharmony_ci FLASH_PACKAGE_TIMEOUT); 24808c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, fw->size, kmem, 24818c2ecf20Sopenharmony_ci dma_handle); 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci release_firmware(fw); 24858c2ecf20Sopenharmony_ci if (rc) 24868c2ecf20Sopenharmony_ci goto err_exit; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci if ((install_type & 0xffff) == 0) 24898c2ecf20Sopenharmony_ci install_type >>= 16; 24908c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1); 24918c2ecf20Sopenharmony_ci install.install_type = cpu_to_le32(install_type); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 24948c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &install, sizeof(install), 24958c2ecf20Sopenharmony_ci INSTALL_PACKAGE_TIMEOUT); 24968c2ecf20Sopenharmony_ci if (rc) { 24978c2ecf20Sopenharmony_ci u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci if (resp->error_code && error_code == 25008c2ecf20Sopenharmony_ci NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { 25018c2ecf20Sopenharmony_ci install.flags |= cpu_to_le16( 25028c2ecf20Sopenharmony_ci NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 25038c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &install, sizeof(install), 25048c2ecf20Sopenharmony_ci INSTALL_PACKAGE_TIMEOUT); 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci if (rc) 25078c2ecf20Sopenharmony_ci goto flash_pkg_exit; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (resp->result) { 25118c2ecf20Sopenharmony_ci netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 25128c2ecf20Sopenharmony_ci (s8)resp->result, (int)resp->problem_item); 25138c2ecf20Sopenharmony_ci rc = -ENOPKG; 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ciflash_pkg_exit: 25168c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 25178c2ecf20Sopenharmony_cierr_exit: 25188c2ecf20Sopenharmony_ci if (rc == -EACCES) 25198c2ecf20Sopenharmony_ci bnxt_print_admin_err(bp); 25208c2ecf20Sopenharmony_ci return rc; 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic int bnxt_flash_device(struct net_device *dev, 25248c2ecf20Sopenharmony_ci struct ethtool_flash *flash) 25258c2ecf20Sopenharmony_ci{ 25268c2ecf20Sopenharmony_ci if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 25278c2ecf20Sopenharmony_ci netdev_err(dev, "flashdev not supported from a virtual function\n"); 25288c2ecf20Sopenharmony_ci return -EINVAL; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 25328c2ecf20Sopenharmony_ci flash->region > 0xffff) 25338c2ecf20Sopenharmony_ci return bnxt_flash_package_from_file(dev, flash->data, 25348c2ecf20Sopenharmony_ci flash->region); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 25378c2ecf20Sopenharmony_ci} 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_cistatic int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 25408c2ecf20Sopenharmony_ci{ 25418c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 25428c2ecf20Sopenharmony_ci int rc; 25438c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dir_info_input req = {0}; 25448c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dir_info_output *output = bp->hwrm_cmd_resp_addr; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_INFO, -1, -1); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 25498c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 25508c2ecf20Sopenharmony_ci if (!rc) { 25518c2ecf20Sopenharmony_ci *entries = le32_to_cpu(output->entries); 25528c2ecf20Sopenharmony_ci *length = le32_to_cpu(output->entry_length); 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 25558c2ecf20Sopenharmony_ci return rc; 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_cistatic int bnxt_get_eeprom_len(struct net_device *dev) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci if (BNXT_VF(bp)) 25638c2ecf20Sopenharmony_ci return 0; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci /* The -1 return value allows the entire 32-bit range of offsets to be 25668c2ecf20Sopenharmony_ci * passed via the ethtool command-line utility. 25678c2ecf20Sopenharmony_ci */ 25688c2ecf20Sopenharmony_ci return -1; 25698c2ecf20Sopenharmony_ci} 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_cistatic int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 25728c2ecf20Sopenharmony_ci{ 25738c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 25748c2ecf20Sopenharmony_ci int rc; 25758c2ecf20Sopenharmony_ci u32 dir_entries; 25768c2ecf20Sopenharmony_ci u32 entry_length; 25778c2ecf20Sopenharmony_ci u8 *buf; 25788c2ecf20Sopenharmony_ci size_t buflen; 25798c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 25808c2ecf20Sopenharmony_ci struct hwrm_nvm_get_dir_entries_input req = {0}; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 25838c2ecf20Sopenharmony_ci if (rc != 0) 25848c2ecf20Sopenharmony_ci return rc; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci if (!dir_entries || !entry_length) 25878c2ecf20Sopenharmony_ci return -EIO; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci /* Insert 2 bytes of directory info (count and size of entries) */ 25908c2ecf20Sopenharmony_ci if (len < 2) 25918c2ecf20Sopenharmony_ci return -EINVAL; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci *data++ = dir_entries; 25948c2ecf20Sopenharmony_ci *data++ = entry_length; 25958c2ecf20Sopenharmony_ci len -= 2; 25968c2ecf20Sopenharmony_ci memset(data, 0xff, len); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci buflen = dir_entries * entry_length; 25998c2ecf20Sopenharmony_ci buf = dma_alloc_coherent(&bp->pdev->dev, buflen, &dma_handle, 26008c2ecf20Sopenharmony_ci GFP_KERNEL); 26018c2ecf20Sopenharmony_ci if (!buf) { 26028c2ecf20Sopenharmony_ci netdev_err(dev, "dma_alloc_coherent failure, length = %u\n", 26038c2ecf20Sopenharmony_ci (unsigned)buflen); 26048c2ecf20Sopenharmony_ci return -ENOMEM; 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_ENTRIES, -1, -1); 26078c2ecf20Sopenharmony_ci req.host_dest_addr = cpu_to_le64(dma_handle); 26088c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 26098c2ecf20Sopenharmony_ci if (rc == 0) 26108c2ecf20Sopenharmony_ci memcpy(data, buf, len > buflen ? buflen : len); 26118c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, buflen, buf, dma_handle); 26128c2ecf20Sopenharmony_ci return rc; 26138c2ecf20Sopenharmony_ci} 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_cistatic int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 26168c2ecf20Sopenharmony_ci u32 length, u8 *data) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 26198c2ecf20Sopenharmony_ci int rc; 26208c2ecf20Sopenharmony_ci u8 *buf; 26218c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 26228c2ecf20Sopenharmony_ci struct hwrm_nvm_read_input req = {0}; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (!length) 26258c2ecf20Sopenharmony_ci return -EINVAL; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci buf = dma_alloc_coherent(&bp->pdev->dev, length, &dma_handle, 26288c2ecf20Sopenharmony_ci GFP_KERNEL); 26298c2ecf20Sopenharmony_ci if (!buf) { 26308c2ecf20Sopenharmony_ci netdev_err(dev, "dma_alloc_coherent failure, length = %u\n", 26318c2ecf20Sopenharmony_ci (unsigned)length); 26328c2ecf20Sopenharmony_ci return -ENOMEM; 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_READ, -1, -1); 26358c2ecf20Sopenharmony_ci req.host_dest_addr = cpu_to_le64(dma_handle); 26368c2ecf20Sopenharmony_ci req.dir_idx = cpu_to_le16(index); 26378c2ecf20Sopenharmony_ci req.offset = cpu_to_le32(offset); 26388c2ecf20Sopenharmony_ci req.len = cpu_to_le32(length); 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 26418c2ecf20Sopenharmony_ci if (rc == 0) 26428c2ecf20Sopenharmony_ci memcpy(data, buf, length); 26438c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, length, buf, dma_handle); 26448c2ecf20Sopenharmony_ci return rc; 26458c2ecf20Sopenharmony_ci} 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_cistatic int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 26488c2ecf20Sopenharmony_ci u16 ext, u16 *index, u32 *item_length, 26498c2ecf20Sopenharmony_ci u32 *data_length) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 26528c2ecf20Sopenharmony_ci int rc; 26538c2ecf20Sopenharmony_ci struct hwrm_nvm_find_dir_entry_input req = {0}; 26548c2ecf20Sopenharmony_ci struct hwrm_nvm_find_dir_entry_output *output = bp->hwrm_cmd_resp_addr; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_FIND_DIR_ENTRY, -1, -1); 26578c2ecf20Sopenharmony_ci req.enables = 0; 26588c2ecf20Sopenharmony_ci req.dir_idx = 0; 26598c2ecf20Sopenharmony_ci req.dir_type = cpu_to_le16(type); 26608c2ecf20Sopenharmony_ci req.dir_ordinal = cpu_to_le16(ordinal); 26618c2ecf20Sopenharmony_ci req.dir_ext = cpu_to_le16(ext); 26628c2ecf20Sopenharmony_ci req.opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 26638c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 26648c2ecf20Sopenharmony_ci rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 26658c2ecf20Sopenharmony_ci if (rc == 0) { 26668c2ecf20Sopenharmony_ci if (index) 26678c2ecf20Sopenharmony_ci *index = le16_to_cpu(output->dir_idx); 26688c2ecf20Sopenharmony_ci if (item_length) 26698c2ecf20Sopenharmony_ci *item_length = le32_to_cpu(output->dir_item_length); 26708c2ecf20Sopenharmony_ci if (data_length) 26718c2ecf20Sopenharmony_ci *data_length = le32_to_cpu(output->dir_data_length); 26728c2ecf20Sopenharmony_ci } 26738c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 26748c2ecf20Sopenharmony_ci return rc; 26758c2ecf20Sopenharmony_ci} 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_cistatic char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 26788c2ecf20Sopenharmony_ci{ 26798c2ecf20Sopenharmony_ci char *retval = NULL; 26808c2ecf20Sopenharmony_ci char *p; 26818c2ecf20Sopenharmony_ci char *value; 26828c2ecf20Sopenharmony_ci int field = 0; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci if (datalen < 1) 26858c2ecf20Sopenharmony_ci return NULL; 26868c2ecf20Sopenharmony_ci /* null-terminate the log data (removing last '\n'): */ 26878c2ecf20Sopenharmony_ci data[datalen - 1] = 0; 26888c2ecf20Sopenharmony_ci for (p = data; *p != 0; p++) { 26898c2ecf20Sopenharmony_ci field = 0; 26908c2ecf20Sopenharmony_ci retval = NULL; 26918c2ecf20Sopenharmony_ci while (*p != 0 && *p != '\n') { 26928c2ecf20Sopenharmony_ci value = p; 26938c2ecf20Sopenharmony_ci while (*p != 0 && *p != '\t' && *p != '\n') 26948c2ecf20Sopenharmony_ci p++; 26958c2ecf20Sopenharmony_ci if (field == desired_field) 26968c2ecf20Sopenharmony_ci retval = value; 26978c2ecf20Sopenharmony_ci if (*p != '\t') 26988c2ecf20Sopenharmony_ci break; 26998c2ecf20Sopenharmony_ci *p = 0; 27008c2ecf20Sopenharmony_ci field++; 27018c2ecf20Sopenharmony_ci p++; 27028c2ecf20Sopenharmony_ci } 27038c2ecf20Sopenharmony_ci if (*p == 0) 27048c2ecf20Sopenharmony_ci break; 27058c2ecf20Sopenharmony_ci *p = 0; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci return retval; 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_cistatic void bnxt_get_pkgver(struct net_device *dev) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 27138c2ecf20Sopenharmony_ci u16 index = 0; 27148c2ecf20Sopenharmony_ci char *pkgver; 27158c2ecf20Sopenharmony_ci u32 pkglen; 27168c2ecf20Sopenharmony_ci u8 *pkgbuf; 27178c2ecf20Sopenharmony_ci int len; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 27208c2ecf20Sopenharmony_ci BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 27218c2ecf20Sopenharmony_ci &index, NULL, &pkglen) != 0) 27228c2ecf20Sopenharmony_ci return; 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci pkgbuf = kzalloc(pkglen, GFP_KERNEL); 27258c2ecf20Sopenharmony_ci if (!pkgbuf) { 27268c2ecf20Sopenharmony_ci dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 27278c2ecf20Sopenharmony_ci pkglen); 27288c2ecf20Sopenharmony_ci return; 27298c2ecf20Sopenharmony_ci } 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci if (bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf)) 27328c2ecf20Sopenharmony_ci goto err; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 27358c2ecf20Sopenharmony_ci pkglen); 27368c2ecf20Sopenharmony_ci if (pkgver && *pkgver != 0 && isdigit(*pkgver)) { 27378c2ecf20Sopenharmony_ci len = strlen(bp->fw_ver_str); 27388c2ecf20Sopenharmony_ci snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 27398c2ecf20Sopenharmony_ci "/pkg %s", pkgver); 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_cierr: 27428c2ecf20Sopenharmony_ci kfree(pkgbuf); 27438c2ecf20Sopenharmony_ci} 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_cistatic int bnxt_get_eeprom(struct net_device *dev, 27468c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, 27478c2ecf20Sopenharmony_ci u8 *data) 27488c2ecf20Sopenharmony_ci{ 27498c2ecf20Sopenharmony_ci u32 index; 27508c2ecf20Sopenharmony_ci u32 offset; 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (eeprom->offset == 0) /* special offset value to get directory */ 27538c2ecf20Sopenharmony_ci return bnxt_get_nvram_directory(dev, eeprom->len, data); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci index = eeprom->offset >> 24; 27568c2ecf20Sopenharmony_ci offset = eeprom->offset & 0xffffff; 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci if (index == 0) { 27598c2ecf20Sopenharmony_ci netdev_err(dev, "unsupported index value: %d\n", index); 27608c2ecf20Sopenharmony_ci return -EINVAL; 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 27648c2ecf20Sopenharmony_ci} 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_cistatic int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 27678c2ecf20Sopenharmony_ci{ 27688c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 27698c2ecf20Sopenharmony_ci struct hwrm_nvm_erase_dir_entry_input req = {0}; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_ERASE_DIR_ENTRY, -1, -1); 27728c2ecf20Sopenharmony_ci req.dir_idx = cpu_to_le16(index); 27738c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 27748c2ecf20Sopenharmony_ci} 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_cistatic int bnxt_set_eeprom(struct net_device *dev, 27778c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, 27788c2ecf20Sopenharmony_ci u8 *data) 27798c2ecf20Sopenharmony_ci{ 27808c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 27818c2ecf20Sopenharmony_ci u8 index, dir_op; 27828c2ecf20Sopenharmony_ci u16 type, ext, ordinal, attr; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (!BNXT_PF(bp)) { 27858c2ecf20Sopenharmony_ci netdev_err(dev, "NVM write not supported from a virtual function\n"); 27868c2ecf20Sopenharmony_ci return -EINVAL; 27878c2ecf20Sopenharmony_ci } 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci type = eeprom->magic >> 16; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci if (type == 0xffff) { /* special value for directory operations */ 27928c2ecf20Sopenharmony_ci index = eeprom->magic & 0xff; 27938c2ecf20Sopenharmony_ci dir_op = eeprom->magic >> 8; 27948c2ecf20Sopenharmony_ci if (index == 0) 27958c2ecf20Sopenharmony_ci return -EINVAL; 27968c2ecf20Sopenharmony_ci switch (dir_op) { 27978c2ecf20Sopenharmony_ci case 0x0e: /* erase */ 27988c2ecf20Sopenharmony_ci if (eeprom->offset != ~eeprom->magic) 27998c2ecf20Sopenharmony_ci return -EINVAL; 28008c2ecf20Sopenharmony_ci return bnxt_erase_nvram_directory(dev, index - 1); 28018c2ecf20Sopenharmony_ci default: 28028c2ecf20Sopenharmony_ci return -EINVAL; 28038c2ecf20Sopenharmony_ci } 28048c2ecf20Sopenharmony_ci } 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci /* Create or re-write an NVM item: */ 28078c2ecf20Sopenharmony_ci if (bnxt_dir_type_is_executable(type)) 28088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 28098c2ecf20Sopenharmony_ci ext = eeprom->magic & 0xffff; 28108c2ecf20Sopenharmony_ci ordinal = eeprom->offset >> 16; 28118c2ecf20Sopenharmony_ci attr = eeprom->offset & 0xffff; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci return bnxt_flash_nvram(dev, type, ordinal, ext, attr, data, 28148c2ecf20Sopenharmony_ci eeprom->len); 28158c2ecf20Sopenharmony_ci} 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_cistatic int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 28188c2ecf20Sopenharmony_ci{ 28198c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 28208c2ecf20Sopenharmony_ci struct ethtool_eee *eee = &bp->eee; 28218c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 28228c2ecf20Sopenharmony_ci u32 advertising; 28238c2ecf20Sopenharmony_ci int rc = 0; 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 28268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_EEE_CAP)) 28298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci mutex_lock(&bp->link_lock); 28328c2ecf20Sopenharmony_ci advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 28338c2ecf20Sopenharmony_ci if (!edata->eee_enabled) 28348c2ecf20Sopenharmony_ci goto eee_ok; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 28378c2ecf20Sopenharmony_ci netdev_warn(dev, "EEE requires autoneg\n"); 28388c2ecf20Sopenharmony_ci rc = -EINVAL; 28398c2ecf20Sopenharmony_ci goto eee_exit; 28408c2ecf20Sopenharmony_ci } 28418c2ecf20Sopenharmony_ci if (edata->tx_lpi_enabled) { 28428c2ecf20Sopenharmony_ci if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 28438c2ecf20Sopenharmony_ci edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 28448c2ecf20Sopenharmony_ci netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 28458c2ecf20Sopenharmony_ci bp->lpi_tmr_lo, bp->lpi_tmr_hi); 28468c2ecf20Sopenharmony_ci rc = -EINVAL; 28478c2ecf20Sopenharmony_ci goto eee_exit; 28488c2ecf20Sopenharmony_ci } else if (!bp->lpi_tmr_hi) { 28498c2ecf20Sopenharmony_ci edata->tx_lpi_timer = eee->tx_lpi_timer; 28508c2ecf20Sopenharmony_ci } 28518c2ecf20Sopenharmony_ci } 28528c2ecf20Sopenharmony_ci if (!edata->advertised) { 28538c2ecf20Sopenharmony_ci edata->advertised = advertising & eee->supported; 28548c2ecf20Sopenharmony_ci } else if (edata->advertised & ~advertising) { 28558c2ecf20Sopenharmony_ci netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 28568c2ecf20Sopenharmony_ci edata->advertised, advertising); 28578c2ecf20Sopenharmony_ci rc = -EINVAL; 28588c2ecf20Sopenharmony_ci goto eee_exit; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci eee->advertised = edata->advertised; 28628c2ecf20Sopenharmony_ci eee->tx_lpi_enabled = edata->tx_lpi_enabled; 28638c2ecf20Sopenharmony_ci eee->tx_lpi_timer = edata->tx_lpi_timer; 28648c2ecf20Sopenharmony_cieee_ok: 28658c2ecf20Sopenharmony_ci eee->eee_enabled = edata->eee_enabled; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci if (netif_running(dev)) 28688c2ecf20Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, false, true); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_cieee_exit: 28718c2ecf20Sopenharmony_ci mutex_unlock(&bp->link_lock); 28728c2ecf20Sopenharmony_ci return rc; 28738c2ecf20Sopenharmony_ci} 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_cistatic int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 28768c2ecf20Sopenharmony_ci{ 28778c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (!(bp->flags & BNXT_FLAG_EEE_CAP)) 28808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci *edata = bp->eee; 28838c2ecf20Sopenharmony_ci if (!bp->eee.eee_enabled) { 28848c2ecf20Sopenharmony_ci /* Preserve tx_lpi_timer so that the last value will be used 28858c2ecf20Sopenharmony_ci * by default when it is re-enabled. 28868c2ecf20Sopenharmony_ci */ 28878c2ecf20Sopenharmony_ci edata->advertised = 0; 28888c2ecf20Sopenharmony_ci edata->tx_lpi_enabled = 0; 28898c2ecf20Sopenharmony_ci } 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci if (!bp->eee.eee_active) 28928c2ecf20Sopenharmony_ci edata->lp_advertised = 0; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci return 0; 28958c2ecf20Sopenharmony_ci} 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_cistatic int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 28988c2ecf20Sopenharmony_ci u16 page_number, u16 start_addr, 28998c2ecf20Sopenharmony_ci u16 data_length, u8 *buf) 29008c2ecf20Sopenharmony_ci{ 29018c2ecf20Sopenharmony_ci struct hwrm_port_phy_i2c_read_input req = {0}; 29028c2ecf20Sopenharmony_ci struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr; 29038c2ecf20Sopenharmony_ci int rc, byte_offset = 0; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1); 29068c2ecf20Sopenharmony_ci req.i2c_slave_addr = i2c_addr; 29078c2ecf20Sopenharmony_ci req.page_number = cpu_to_le16(page_number); 29088c2ecf20Sopenharmony_ci req.port_id = cpu_to_le16(bp->pf.port_id); 29098c2ecf20Sopenharmony_ci do { 29108c2ecf20Sopenharmony_ci u16 xfer_size; 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 29138c2ecf20Sopenharmony_ci data_length -= xfer_size; 29148c2ecf20Sopenharmony_ci req.page_offset = cpu_to_le16(start_addr + byte_offset); 29158c2ecf20Sopenharmony_ci req.data_length = xfer_size; 29168c2ecf20Sopenharmony_ci req.enables = cpu_to_le32(start_addr + byte_offset ? 29178c2ecf20Sopenharmony_ci PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); 29188c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 29198c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), 29208c2ecf20Sopenharmony_ci HWRM_CMD_TIMEOUT); 29218c2ecf20Sopenharmony_ci if (!rc) 29228c2ecf20Sopenharmony_ci memcpy(buf + byte_offset, output->data, xfer_size); 29238c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 29248c2ecf20Sopenharmony_ci byte_offset += xfer_size; 29258c2ecf20Sopenharmony_ci } while (!rc && data_length > 0); 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci return rc; 29288c2ecf20Sopenharmony_ci} 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_cistatic int bnxt_get_module_info(struct net_device *dev, 29318c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 29328c2ecf20Sopenharmony_ci{ 29338c2ecf20Sopenharmony_ci u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 29348c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 29358c2ecf20Sopenharmony_ci int rc; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci /* No point in going further if phy status indicates 29388c2ecf20Sopenharmony_ci * module is not inserted or if it is powered down or 29398c2ecf20Sopenharmony_ci * if it is of type 10GBase-T 29408c2ecf20Sopenharmony_ci */ 29418c2ecf20Sopenharmony_ci if (bp->link_info.module_status > 29428c2ecf20Sopenharmony_ci PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 29438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci /* This feature is not supported in older firmware versions */ 29468c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code < 0x10202) 29478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 29508c2ecf20Sopenharmony_ci SFF_DIAG_SUPPORT_OFFSET + 1, 29518c2ecf20Sopenharmony_ci data); 29528c2ecf20Sopenharmony_ci if (!rc) { 29538c2ecf20Sopenharmony_ci u8 module_id = data[0]; 29548c2ecf20Sopenharmony_ci u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci switch (module_id) { 29578c2ecf20Sopenharmony_ci case SFF_MODULE_ID_SFP: 29588c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 29598c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 29608c2ecf20Sopenharmony_ci if (!diag_supported) 29618c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 29628c2ecf20Sopenharmony_ci break; 29638c2ecf20Sopenharmony_ci case SFF_MODULE_ID_QSFP: 29648c2ecf20Sopenharmony_ci case SFF_MODULE_ID_QSFP_PLUS: 29658c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 29668c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 29678c2ecf20Sopenharmony_ci break; 29688c2ecf20Sopenharmony_ci case SFF_MODULE_ID_QSFP28: 29698c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 29708c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 29718c2ecf20Sopenharmony_ci break; 29728c2ecf20Sopenharmony_ci default: 29738c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 29748c2ecf20Sopenharmony_ci break; 29758c2ecf20Sopenharmony_ci } 29768c2ecf20Sopenharmony_ci } 29778c2ecf20Sopenharmony_ci return rc; 29788c2ecf20Sopenharmony_ci} 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_cistatic int bnxt_get_module_eeprom(struct net_device *dev, 29818c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, 29828c2ecf20Sopenharmony_ci u8 *data) 29838c2ecf20Sopenharmony_ci{ 29848c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 29858c2ecf20Sopenharmony_ci u16 start = eeprom->offset, length = eeprom->len; 29868c2ecf20Sopenharmony_ci int rc = 0; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci memset(data, 0, eeprom->len); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci /* Read A0 portion of the EEPROM */ 29918c2ecf20Sopenharmony_ci if (start < ETH_MODULE_SFF_8436_LEN) { 29928c2ecf20Sopenharmony_ci if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 29938c2ecf20Sopenharmony_ci length = ETH_MODULE_SFF_8436_LEN - start; 29948c2ecf20Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 29958c2ecf20Sopenharmony_ci start, length, data); 29968c2ecf20Sopenharmony_ci if (rc) 29978c2ecf20Sopenharmony_ci return rc; 29988c2ecf20Sopenharmony_ci start += length; 29998c2ecf20Sopenharmony_ci data += length; 30008c2ecf20Sopenharmony_ci length = eeprom->len - length; 30018c2ecf20Sopenharmony_ci } 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci /* Read A2 portion of the EEPROM */ 30048c2ecf20Sopenharmony_ci if (length) { 30058c2ecf20Sopenharmony_ci start -= ETH_MODULE_SFF_8436_LEN; 30068c2ecf20Sopenharmony_ci rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 30078c2ecf20Sopenharmony_ci start, length, data); 30088c2ecf20Sopenharmony_ci } 30098c2ecf20Sopenharmony_ci return rc; 30108c2ecf20Sopenharmony_ci} 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_cistatic int bnxt_nway_reset(struct net_device *dev) 30138c2ecf20Sopenharmony_ci{ 30148c2ecf20Sopenharmony_ci int rc = 0; 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 30178c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci if (!BNXT_PHY_CFG_ABLE(bp)) 30208c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 30238c2ecf20Sopenharmony_ci return -EINVAL; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (netif_running(dev)) 30268c2ecf20Sopenharmony_ci rc = bnxt_hwrm_set_link_setting(bp, true, false); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci return rc; 30298c2ecf20Sopenharmony_ci} 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_cistatic int bnxt_set_phys_id(struct net_device *dev, 30328c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 30338c2ecf20Sopenharmony_ci{ 30348c2ecf20Sopenharmony_ci struct hwrm_port_led_cfg_input req = {0}; 30358c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 30368c2ecf20Sopenharmony_ci struct bnxt_pf_info *pf = &bp->pf; 30378c2ecf20Sopenharmony_ci struct bnxt_led_cfg *led_cfg; 30388c2ecf20Sopenharmony_ci u8 led_state; 30398c2ecf20Sopenharmony_ci __le16 duration; 30408c2ecf20Sopenharmony_ci int i; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if (!bp->num_leds || BNXT_VF(bp)) 30438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci if (state == ETHTOOL_ID_ACTIVE) { 30468c2ecf20Sopenharmony_ci led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 30478c2ecf20Sopenharmony_ci duration = cpu_to_le16(500); 30488c2ecf20Sopenharmony_ci } else if (state == ETHTOOL_ID_INACTIVE) { 30498c2ecf20Sopenharmony_ci led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 30508c2ecf20Sopenharmony_ci duration = cpu_to_le16(0); 30518c2ecf20Sopenharmony_ci } else { 30528c2ecf20Sopenharmony_ci return -EINVAL; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_LED_CFG, -1, -1); 30558c2ecf20Sopenharmony_ci req.port_id = cpu_to_le16(pf->port_id); 30568c2ecf20Sopenharmony_ci req.num_leds = bp->num_leds; 30578c2ecf20Sopenharmony_ci led_cfg = (struct bnxt_led_cfg *)&req.led0_id; 30588c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_leds; i++, led_cfg++) { 30598c2ecf20Sopenharmony_ci req.enables |= BNXT_LED_DFLT_ENABLES(i); 30608c2ecf20Sopenharmony_ci led_cfg->led_id = bp->leds[i].led_id; 30618c2ecf20Sopenharmony_ci led_cfg->led_state = led_state; 30628c2ecf20Sopenharmony_ci led_cfg->led_blink_on = duration; 30638c2ecf20Sopenharmony_ci led_cfg->led_blink_off = duration; 30648c2ecf20Sopenharmony_ci led_cfg->led_group_id = bp->leds[i].led_group_id; 30658c2ecf20Sopenharmony_ci } 30668c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 30678c2ecf20Sopenharmony_ci} 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_cistatic int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 30708c2ecf20Sopenharmony_ci{ 30718c2ecf20Sopenharmony_ci struct hwrm_selftest_irq_input req = {0}; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_IRQ, cmpl_ring, -1); 30748c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 30758c2ecf20Sopenharmony_ci} 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_cistatic int bnxt_test_irq(struct bnxt *bp) 30788c2ecf20Sopenharmony_ci{ 30798c2ecf20Sopenharmony_ci int i; 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci for (i = 0; i < bp->cp_nr_rings; i++) { 30828c2ecf20Sopenharmony_ci u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 30838c2ecf20Sopenharmony_ci int rc; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 30868c2ecf20Sopenharmony_ci if (rc) 30878c2ecf20Sopenharmony_ci return rc; 30888c2ecf20Sopenharmony_ci } 30898c2ecf20Sopenharmony_ci return 0; 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_cistatic int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 30938c2ecf20Sopenharmony_ci{ 30948c2ecf20Sopenharmony_ci struct hwrm_port_mac_cfg_input req = {0}; 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1); 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 30998c2ecf20Sopenharmony_ci if (enable) 31008c2ecf20Sopenharmony_ci req.lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 31018c2ecf20Sopenharmony_ci else 31028c2ecf20Sopenharmony_ci req.lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 31038c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 31048c2ecf20Sopenharmony_ci} 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_cistatic int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 31078c2ecf20Sopenharmony_ci{ 31088c2ecf20Sopenharmony_ci struct hwrm_port_phy_qcaps_output *resp = bp->hwrm_cmd_resp_addr; 31098c2ecf20Sopenharmony_ci struct hwrm_port_phy_qcaps_input req = {0}; 31108c2ecf20Sopenharmony_ci int rc; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_QCAPS, -1, -1); 31138c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 31148c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 31158c2ecf20Sopenharmony_ci if (!rc) 31168c2ecf20Sopenharmony_ci *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 31198c2ecf20Sopenharmony_ci return rc; 31208c2ecf20Sopenharmony_ci} 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_cistatic int bnxt_disable_an_for_lpbk(struct bnxt *bp, 31238c2ecf20Sopenharmony_ci struct hwrm_port_phy_cfg_input *req) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci struct bnxt_link_info *link_info = &bp->link_info; 31268c2ecf20Sopenharmony_ci u16 fw_advertising; 31278c2ecf20Sopenharmony_ci u16 fw_speed; 31288c2ecf20Sopenharmony_ci int rc; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci if (!link_info->autoneg || 31318c2ecf20Sopenharmony_ci (bp->test_info->flags & BNXT_TEST_FL_AN_PHY_LPBK)) 31328c2ecf20Sopenharmony_ci return 0; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci rc = bnxt_query_force_speeds(bp, &fw_advertising); 31358c2ecf20Sopenharmony_ci if (rc) 31368c2ecf20Sopenharmony_ci return rc; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 31398c2ecf20Sopenharmony_ci if (bp->link_info.link_up) 31408c2ecf20Sopenharmony_ci fw_speed = bp->link_info.link_speed; 31418c2ecf20Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 31428c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 31438c2ecf20Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 31448c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 31458c2ecf20Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 31468c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 31478c2ecf20Sopenharmony_ci else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 31488c2ecf20Sopenharmony_ci fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci req->force_link_speed = cpu_to_le16(fw_speed); 31518c2ecf20Sopenharmony_ci req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 31528c2ecf20Sopenharmony_ci PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 31538c2ecf20Sopenharmony_ci rc = hwrm_send_message(bp, req, sizeof(*req), HWRM_CMD_TIMEOUT); 31548c2ecf20Sopenharmony_ci req->flags = 0; 31558c2ecf20Sopenharmony_ci req->force_link_speed = cpu_to_le16(0); 31568c2ecf20Sopenharmony_ci return rc; 31578c2ecf20Sopenharmony_ci} 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_cistatic int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 31608c2ecf20Sopenharmony_ci{ 31618c2ecf20Sopenharmony_ci struct hwrm_port_phy_cfg_input req = {0}; 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1); 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if (enable) { 31668c2ecf20Sopenharmony_ci bnxt_disable_an_for_lpbk(bp, &req); 31678c2ecf20Sopenharmony_ci if (ext) 31688c2ecf20Sopenharmony_ci req.lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 31698c2ecf20Sopenharmony_ci else 31708c2ecf20Sopenharmony_ci req.lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 31718c2ecf20Sopenharmony_ci } else { 31728c2ecf20Sopenharmony_ci req.lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci req.enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 31758c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 31768c2ecf20Sopenharmony_ci} 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_cistatic int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 31798c2ecf20Sopenharmony_ci u32 raw_cons, int pkt_size) 31808c2ecf20Sopenharmony_ci{ 31818c2ecf20Sopenharmony_ci struct bnxt_napi *bnapi = cpr->bnapi; 31828c2ecf20Sopenharmony_ci struct bnxt_rx_ring_info *rxr; 31838c2ecf20Sopenharmony_ci struct bnxt_sw_rx_bd *rx_buf; 31848c2ecf20Sopenharmony_ci struct rx_cmp *rxcmp; 31858c2ecf20Sopenharmony_ci u16 cp_cons, cons; 31868c2ecf20Sopenharmony_ci u8 *data; 31878c2ecf20Sopenharmony_ci u32 len; 31888c2ecf20Sopenharmony_ci int i; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci rxr = bnapi->rx_ring; 31918c2ecf20Sopenharmony_ci cp_cons = RING_CMP(raw_cons); 31928c2ecf20Sopenharmony_ci rxcmp = (struct rx_cmp *) 31938c2ecf20Sopenharmony_ci &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 31948c2ecf20Sopenharmony_ci cons = rxcmp->rx_cmp_opaque; 31958c2ecf20Sopenharmony_ci rx_buf = &rxr->rx_buf_ring[cons]; 31968c2ecf20Sopenharmony_ci data = rx_buf->data_ptr; 31978c2ecf20Sopenharmony_ci len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 31988c2ecf20Sopenharmony_ci if (len != pkt_size) 31998c2ecf20Sopenharmony_ci return -EIO; 32008c2ecf20Sopenharmony_ci i = ETH_ALEN; 32018c2ecf20Sopenharmony_ci if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 32028c2ecf20Sopenharmony_ci return -EIO; 32038c2ecf20Sopenharmony_ci i += ETH_ALEN; 32048c2ecf20Sopenharmony_ci for ( ; i < pkt_size; i++) { 32058c2ecf20Sopenharmony_ci if (data[i] != (u8)(i & 0xff)) 32068c2ecf20Sopenharmony_ci return -EIO; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci return 0; 32098c2ecf20Sopenharmony_ci} 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_cistatic int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 32128c2ecf20Sopenharmony_ci int pkt_size) 32138c2ecf20Sopenharmony_ci{ 32148c2ecf20Sopenharmony_ci struct tx_cmp *txcmp; 32158c2ecf20Sopenharmony_ci int rc = -EIO; 32168c2ecf20Sopenharmony_ci u32 raw_cons; 32178c2ecf20Sopenharmony_ci u32 cons; 32188c2ecf20Sopenharmony_ci int i; 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci raw_cons = cpr->cp_raw_cons; 32218c2ecf20Sopenharmony_ci for (i = 0; i < 200; i++) { 32228c2ecf20Sopenharmony_ci cons = RING_CMP(raw_cons); 32238c2ecf20Sopenharmony_ci txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci if (!TX_CMP_VALID(txcmp, raw_cons)) { 32268c2ecf20Sopenharmony_ci udelay(5); 32278c2ecf20Sopenharmony_ci continue; 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci /* The valid test of the entry must be done first before 32318c2ecf20Sopenharmony_ci * reading any further. 32328c2ecf20Sopenharmony_ci */ 32338c2ecf20Sopenharmony_ci dma_rmb(); 32348c2ecf20Sopenharmony_ci if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 32358c2ecf20Sopenharmony_ci rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 32368c2ecf20Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 32378c2ecf20Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 32388c2ecf20Sopenharmony_ci break; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci raw_cons = NEXT_RAW_CMP(raw_cons); 32418c2ecf20Sopenharmony_ci } 32428c2ecf20Sopenharmony_ci cpr->cp_raw_cons = raw_cons; 32438c2ecf20Sopenharmony_ci return rc; 32448c2ecf20Sopenharmony_ci} 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_cistatic int bnxt_run_loopback(struct bnxt *bp) 32478c2ecf20Sopenharmony_ci{ 32488c2ecf20Sopenharmony_ci struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 32498c2ecf20Sopenharmony_ci struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 32508c2ecf20Sopenharmony_ci struct bnxt_cp_ring_info *cpr; 32518c2ecf20Sopenharmony_ci int pkt_size, i = 0; 32528c2ecf20Sopenharmony_ci struct sk_buff *skb; 32538c2ecf20Sopenharmony_ci dma_addr_t map; 32548c2ecf20Sopenharmony_ci u8 *data; 32558c2ecf20Sopenharmony_ci int rc; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci cpr = &rxr->bnapi->cp_ring; 32588c2ecf20Sopenharmony_ci if (bp->flags & BNXT_FLAG_CHIP_P5) 32598c2ecf20Sopenharmony_ci cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 32608c2ecf20Sopenharmony_ci pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 32618c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, pkt_size); 32628c2ecf20Sopenharmony_ci if (!skb) 32638c2ecf20Sopenharmony_ci return -ENOMEM; 32648c2ecf20Sopenharmony_ci data = skb_put(skb, pkt_size); 32658c2ecf20Sopenharmony_ci eth_broadcast_addr(data); 32668c2ecf20Sopenharmony_ci i += ETH_ALEN; 32678c2ecf20Sopenharmony_ci ether_addr_copy(&data[i], bp->dev->dev_addr); 32688c2ecf20Sopenharmony_ci i += ETH_ALEN; 32698c2ecf20Sopenharmony_ci for ( ; i < pkt_size; i++) 32708c2ecf20Sopenharmony_ci data[i] = (u8)(i & 0xff); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 32738c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 32748c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, map)) { 32758c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 32768c2ecf20Sopenharmony_ci return -EIO; 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci bnxt_xmit_bd(bp, txr, map, pkt_size); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci /* Sync BD data before updating doorbell */ 32818c2ecf20Sopenharmony_ci wmb(); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 32848c2ecf20Sopenharmony_ci rc = bnxt_poll_loopback(bp, cpr, pkt_size); 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); 32878c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 32888c2ecf20Sopenharmony_ci return rc; 32898c2ecf20Sopenharmony_ci} 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_cistatic int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 32928c2ecf20Sopenharmony_ci{ 32938c2ecf20Sopenharmony_ci struct hwrm_selftest_exec_output *resp = bp->hwrm_cmd_resp_addr; 32948c2ecf20Sopenharmony_ci struct hwrm_selftest_exec_input req = {0}; 32958c2ecf20Sopenharmony_ci int rc; 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_EXEC, -1, -1); 32988c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 32998c2ecf20Sopenharmony_ci resp->test_success = 0; 33008c2ecf20Sopenharmony_ci req.flags = test_mask; 33018c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), bp->test_info->timeout); 33028c2ecf20Sopenharmony_ci *test_results = resp->test_success; 33038c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 33048c2ecf20Sopenharmony_ci return rc; 33058c2ecf20Sopenharmony_ci} 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci#define BNXT_DRV_TESTS 4 33088c2ecf20Sopenharmony_ci#define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 33098c2ecf20Sopenharmony_ci#define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 33108c2ecf20Sopenharmony_ci#define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 33118c2ecf20Sopenharmony_ci#define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_cistatic void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 33148c2ecf20Sopenharmony_ci u64 *buf) 33158c2ecf20Sopenharmony_ci{ 33168c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 33178c2ecf20Sopenharmony_ci bool do_ext_lpbk = false; 33188c2ecf20Sopenharmony_ci bool offline = false; 33198c2ecf20Sopenharmony_ci u8 test_results = 0; 33208c2ecf20Sopenharmony_ci u8 test_mask = 0; 33218c2ecf20Sopenharmony_ci int rc = 0, i; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci if (!bp->num_tests || !BNXT_PF(bp)) 33248c2ecf20Sopenharmony_ci return; 33258c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * bp->num_tests); 33268c2ecf20Sopenharmony_ci if (!netif_running(dev)) { 33278c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33288c2ecf20Sopenharmony_ci return; 33298c2ecf20Sopenharmony_ci } 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 33328c2ecf20Sopenharmony_ci (bp->test_info->flags & BNXT_TEST_FL_EXT_LPBK)) 33338c2ecf20Sopenharmony_ci do_ext_lpbk = true; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci if (etest->flags & ETH_TEST_FL_OFFLINE) { 33368c2ecf20Sopenharmony_ci if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 33378c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33388c2ecf20Sopenharmony_ci netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 33398c2ecf20Sopenharmony_ci return; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci offline = true; 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 33458c2ecf20Sopenharmony_ci u8 bit_val = 1 << i; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci if (!(bp->test_info->offline_mask & bit_val)) 33488c2ecf20Sopenharmony_ci test_mask |= bit_val; 33498c2ecf20Sopenharmony_ci else if (offline) 33508c2ecf20Sopenharmony_ci test_mask |= bit_val; 33518c2ecf20Sopenharmony_ci } 33528c2ecf20Sopenharmony_ci if (!offline) { 33538c2ecf20Sopenharmony_ci bnxt_run_fw_tests(bp, test_mask, &test_results); 33548c2ecf20Sopenharmony_ci } else { 33558c2ecf20Sopenharmony_ci rc = bnxt_close_nic(bp, false, false); 33568c2ecf20Sopenharmony_ci if (rc) 33578c2ecf20Sopenharmony_ci return; 33588c2ecf20Sopenharmony_ci bnxt_run_fw_tests(bp, test_mask, &test_results); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci buf[BNXT_MACLPBK_TEST_IDX] = 1; 33618c2ecf20Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, true); 33628c2ecf20Sopenharmony_ci msleep(250); 33638c2ecf20Sopenharmony_ci rc = bnxt_half_open_nic(bp); 33648c2ecf20Sopenharmony_ci if (rc) { 33658c2ecf20Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, false); 33668c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33678c2ecf20Sopenharmony_ci return; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci if (bnxt_run_loopback(bp)) 33708c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33718c2ecf20Sopenharmony_ci else 33728c2ecf20Sopenharmony_ci buf[BNXT_MACLPBK_TEST_IDX] = 0; 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci bnxt_hwrm_mac_loopback(bp, false); 33758c2ecf20Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, true, false); 33768c2ecf20Sopenharmony_ci msleep(1000); 33778c2ecf20Sopenharmony_ci if (bnxt_run_loopback(bp)) { 33788c2ecf20Sopenharmony_ci buf[BNXT_PHYLPBK_TEST_IDX] = 1; 33798c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci if (do_ext_lpbk) { 33828c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 33838c2ecf20Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, true, true); 33848c2ecf20Sopenharmony_ci msleep(1000); 33858c2ecf20Sopenharmony_ci if (bnxt_run_loopback(bp)) { 33868c2ecf20Sopenharmony_ci buf[BNXT_EXTLPBK_TEST_IDX] = 1; 33878c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33888c2ecf20Sopenharmony_ci } 33898c2ecf20Sopenharmony_ci } 33908c2ecf20Sopenharmony_ci bnxt_hwrm_phy_loopback(bp, false, false); 33918c2ecf20Sopenharmony_ci bnxt_half_close_nic(bp); 33928c2ecf20Sopenharmony_ci rc = bnxt_open_nic(bp, false, true); 33938c2ecf20Sopenharmony_ci } 33948c2ecf20Sopenharmony_ci if (rc || bnxt_test_irq(bp)) { 33958c2ecf20Sopenharmony_ci buf[BNXT_IRQ_TEST_IDX] = 1; 33968c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 33978c2ecf20Sopenharmony_ci } 33988c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 33998c2ecf20Sopenharmony_ci u8 bit_val = 1 << i; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci if ((test_mask & bit_val) && !(test_results & bit_val)) { 34028c2ecf20Sopenharmony_ci buf[i] = 1; 34038c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci } 34068c2ecf20Sopenharmony_ci} 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_cistatic int bnxt_reset(struct net_device *dev, u32 *flags) 34098c2ecf20Sopenharmony_ci{ 34108c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 34118c2ecf20Sopenharmony_ci bool reload = false; 34128c2ecf20Sopenharmony_ci u32 req = *flags; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (!req) 34158c2ecf20Sopenharmony_ci return -EINVAL; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci if (!BNXT_PF(bp)) { 34188c2ecf20Sopenharmony_ci netdev_err(dev, "Reset is not supported from a VF\n"); 34198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci if (pci_vfs_assigned(bp->pdev) && 34238c2ecf20Sopenharmony_ci !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 34248c2ecf20Sopenharmony_ci netdev_err(dev, 34258c2ecf20Sopenharmony_ci "Reset not allowed when VFs are assigned to VMs\n"); 34268c2ecf20Sopenharmony_ci return -EBUSY; 34278c2ecf20Sopenharmony_ci } 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 34308c2ecf20Sopenharmony_ci /* This feature is not supported in older firmware versions */ 34318c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code >= 0x10803) { 34328c2ecf20Sopenharmony_ci if (!bnxt_firmware_reset_chip(dev)) { 34338c2ecf20Sopenharmony_ci netdev_info(dev, "Firmware reset request successful.\n"); 34348c2ecf20Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 34358c2ecf20Sopenharmony_ci reload = true; 34368c2ecf20Sopenharmony_ci *flags &= ~BNXT_FW_RESET_CHIP; 34378c2ecf20Sopenharmony_ci } 34388c2ecf20Sopenharmony_ci } else if (req == BNXT_FW_RESET_CHIP) { 34398c2ecf20Sopenharmony_ci return -EOPNOTSUPP; /* only request, fail hard */ 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci } 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) { 34448c2ecf20Sopenharmony_ci /* This feature is not supported in older firmware versions */ 34458c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code >= 0x10803) { 34468c2ecf20Sopenharmony_ci if (!bnxt_firmware_reset_ap(dev)) { 34478c2ecf20Sopenharmony_ci netdev_info(dev, "Reset application processor successful.\n"); 34488c2ecf20Sopenharmony_ci reload = true; 34498c2ecf20Sopenharmony_ci *flags &= ~BNXT_FW_RESET_AP; 34508c2ecf20Sopenharmony_ci } 34518c2ecf20Sopenharmony_ci } else if (req == BNXT_FW_RESET_AP) { 34528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; /* only request, fail hard */ 34538c2ecf20Sopenharmony_ci } 34548c2ecf20Sopenharmony_ci } 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci if (reload) 34578c2ecf20Sopenharmony_ci netdev_info(dev, "Reload driver to complete reset\n"); 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci return 0; 34608c2ecf20Sopenharmony_ci} 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len, 34638c2ecf20Sopenharmony_ci struct bnxt_hwrm_dbg_dma_info *info) 34648c2ecf20Sopenharmony_ci{ 34658c2ecf20Sopenharmony_ci struct hwrm_dbg_cmn_output *cmn_resp = bp->hwrm_cmd_resp_addr; 34668c2ecf20Sopenharmony_ci struct hwrm_dbg_cmn_input *cmn_req = msg; 34678c2ecf20Sopenharmony_ci __le16 *seq_ptr = msg + info->seq_off; 34688c2ecf20Sopenharmony_ci u16 seq = 0, len, segs_off; 34698c2ecf20Sopenharmony_ci void *resp = cmn_resp; 34708c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 34718c2ecf20Sopenharmony_ci int rc, off = 0; 34728c2ecf20Sopenharmony_ci void *dma_buf; 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci dma_buf = dma_alloc_coherent(&bp->pdev->dev, info->dma_len, &dma_handle, 34758c2ecf20Sopenharmony_ci GFP_KERNEL); 34768c2ecf20Sopenharmony_ci if (!dma_buf) 34778c2ecf20Sopenharmony_ci return -ENOMEM; 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci segs_off = offsetof(struct hwrm_dbg_coredump_list_output, 34808c2ecf20Sopenharmony_ci total_segments); 34818c2ecf20Sopenharmony_ci cmn_req->host_dest_addr = cpu_to_le64(dma_handle); 34828c2ecf20Sopenharmony_ci cmn_req->host_buf_len = cpu_to_le32(info->dma_len); 34838c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 34848c2ecf20Sopenharmony_ci while (1) { 34858c2ecf20Sopenharmony_ci *seq_ptr = cpu_to_le16(seq); 34868c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, msg, msg_len, 34878c2ecf20Sopenharmony_ci HWRM_COREDUMP_TIMEOUT); 34888c2ecf20Sopenharmony_ci if (rc) 34898c2ecf20Sopenharmony_ci break; 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci len = le16_to_cpu(*((__le16 *)(resp + info->data_len_off))); 34928c2ecf20Sopenharmony_ci if (!seq && 34938c2ecf20Sopenharmony_ci cmn_req->req_type == cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) { 34948c2ecf20Sopenharmony_ci info->segs = le16_to_cpu(*((__le16 *)(resp + 34958c2ecf20Sopenharmony_ci segs_off))); 34968c2ecf20Sopenharmony_ci if (!info->segs) { 34978c2ecf20Sopenharmony_ci rc = -EIO; 34988c2ecf20Sopenharmony_ci break; 34998c2ecf20Sopenharmony_ci } 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci info->dest_buf_size = info->segs * 35028c2ecf20Sopenharmony_ci sizeof(struct coredump_segment_record); 35038c2ecf20Sopenharmony_ci info->dest_buf = kmalloc(info->dest_buf_size, 35048c2ecf20Sopenharmony_ci GFP_KERNEL); 35058c2ecf20Sopenharmony_ci if (!info->dest_buf) { 35068c2ecf20Sopenharmony_ci rc = -ENOMEM; 35078c2ecf20Sopenharmony_ci break; 35088c2ecf20Sopenharmony_ci } 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci if (info->dest_buf) { 35128c2ecf20Sopenharmony_ci if ((info->seg_start + off + len) <= 35138c2ecf20Sopenharmony_ci BNXT_COREDUMP_BUF_LEN(info->buf_len)) { 35148c2ecf20Sopenharmony_ci memcpy(info->dest_buf + off, dma_buf, len); 35158c2ecf20Sopenharmony_ci } else { 35168c2ecf20Sopenharmony_ci rc = -ENOBUFS; 35178c2ecf20Sopenharmony_ci break; 35188c2ecf20Sopenharmony_ci } 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (cmn_req->req_type == 35228c2ecf20Sopenharmony_ci cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) 35238c2ecf20Sopenharmony_ci info->dest_buf_size += len; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE)) 35268c2ecf20Sopenharmony_ci break; 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci seq++; 35298c2ecf20Sopenharmony_ci off += len; 35308c2ecf20Sopenharmony_ci } 35318c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 35328c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, info->dma_len, dma_buf, dma_handle); 35338c2ecf20Sopenharmony_ci return rc; 35348c2ecf20Sopenharmony_ci} 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_list(struct bnxt *bp, 35378c2ecf20Sopenharmony_ci struct bnxt_coredump *coredump) 35388c2ecf20Sopenharmony_ci{ 35398c2ecf20Sopenharmony_ci struct hwrm_dbg_coredump_list_input req = {0}; 35408c2ecf20Sopenharmony_ci struct bnxt_hwrm_dbg_dma_info info = {NULL}; 35418c2ecf20Sopenharmony_ci int rc; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_LIST, -1, -1); 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci info.dma_len = COREDUMP_LIST_BUF_LEN; 35468c2ecf20Sopenharmony_ci info.seq_off = offsetof(struct hwrm_dbg_coredump_list_input, seq_no); 35478c2ecf20Sopenharmony_ci info.data_len_off = offsetof(struct hwrm_dbg_coredump_list_output, 35488c2ecf20Sopenharmony_ci data_len); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info); 35518c2ecf20Sopenharmony_ci if (!rc) { 35528c2ecf20Sopenharmony_ci coredump->data = info.dest_buf; 35538c2ecf20Sopenharmony_ci coredump->data_size = info.dest_buf_size; 35548c2ecf20Sopenharmony_ci coredump->total_segs = info.segs; 35558c2ecf20Sopenharmony_ci } 35568c2ecf20Sopenharmony_ci return rc; 35578c2ecf20Sopenharmony_ci} 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id, 35608c2ecf20Sopenharmony_ci u16 segment_id) 35618c2ecf20Sopenharmony_ci{ 35628c2ecf20Sopenharmony_ci struct hwrm_dbg_coredump_initiate_input req = {0}; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_INITIATE, -1, -1); 35658c2ecf20Sopenharmony_ci req.component_id = cpu_to_le16(component_id); 35668c2ecf20Sopenharmony_ci req.segment_id = cpu_to_le16(segment_id); 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci return hwrm_send_message(bp, &req, sizeof(req), HWRM_COREDUMP_TIMEOUT); 35698c2ecf20Sopenharmony_ci} 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, 35728c2ecf20Sopenharmony_ci u16 segment_id, u32 *seg_len, 35738c2ecf20Sopenharmony_ci void *buf, u32 buf_len, u32 offset) 35748c2ecf20Sopenharmony_ci{ 35758c2ecf20Sopenharmony_ci struct hwrm_dbg_coredump_retrieve_input req = {0}; 35768c2ecf20Sopenharmony_ci struct bnxt_hwrm_dbg_dma_info info = {NULL}; 35778c2ecf20Sopenharmony_ci int rc; 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_RETRIEVE, -1, -1); 35808c2ecf20Sopenharmony_ci req.component_id = cpu_to_le16(component_id); 35818c2ecf20Sopenharmony_ci req.segment_id = cpu_to_le16(segment_id); 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci info.dma_len = COREDUMP_RETRIEVE_BUF_LEN; 35848c2ecf20Sopenharmony_ci info.seq_off = offsetof(struct hwrm_dbg_coredump_retrieve_input, 35858c2ecf20Sopenharmony_ci seq_no); 35868c2ecf20Sopenharmony_ci info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output, 35878c2ecf20Sopenharmony_ci data_len); 35888c2ecf20Sopenharmony_ci if (buf) { 35898c2ecf20Sopenharmony_ci info.dest_buf = buf + offset; 35908c2ecf20Sopenharmony_ci info.buf_len = buf_len; 35918c2ecf20Sopenharmony_ci info.seg_start = offset; 35928c2ecf20Sopenharmony_ci } 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info); 35958c2ecf20Sopenharmony_ci if (!rc) 35968c2ecf20Sopenharmony_ci *seg_len = info.dest_buf_size; 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci return rc; 35998c2ecf20Sopenharmony_ci} 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_cistatic void 36028c2ecf20Sopenharmony_cibnxt_fill_coredump_seg_hdr(struct bnxt *bp, 36038c2ecf20Sopenharmony_ci struct bnxt_coredump_segment_hdr *seg_hdr, 36048c2ecf20Sopenharmony_ci struct coredump_segment_record *seg_rec, u32 seg_len, 36058c2ecf20Sopenharmony_ci int status, u32 duration, u32 instance) 36068c2ecf20Sopenharmony_ci{ 36078c2ecf20Sopenharmony_ci memset(seg_hdr, 0, sizeof(*seg_hdr)); 36088c2ecf20Sopenharmony_ci memcpy(seg_hdr->signature, "sEgM", 4); 36098c2ecf20Sopenharmony_ci if (seg_rec) { 36108c2ecf20Sopenharmony_ci seg_hdr->component_id = (__force __le32)seg_rec->component_id; 36118c2ecf20Sopenharmony_ci seg_hdr->segment_id = (__force __le32)seg_rec->segment_id; 36128c2ecf20Sopenharmony_ci seg_hdr->low_version = seg_rec->version_low; 36138c2ecf20Sopenharmony_ci seg_hdr->high_version = seg_rec->version_hi; 36148c2ecf20Sopenharmony_ci } else { 36158c2ecf20Sopenharmony_ci /* For hwrm_ver_get response Component id = 2 36168c2ecf20Sopenharmony_ci * and Segment id = 0 36178c2ecf20Sopenharmony_ci */ 36188c2ecf20Sopenharmony_ci seg_hdr->component_id = cpu_to_le32(2); 36198c2ecf20Sopenharmony_ci seg_hdr->segment_id = 0; 36208c2ecf20Sopenharmony_ci } 36218c2ecf20Sopenharmony_ci seg_hdr->function_id = cpu_to_le16(bp->pdev->devfn); 36228c2ecf20Sopenharmony_ci seg_hdr->length = cpu_to_le32(seg_len); 36238c2ecf20Sopenharmony_ci seg_hdr->status = cpu_to_le32(status); 36248c2ecf20Sopenharmony_ci seg_hdr->duration = cpu_to_le32(duration); 36258c2ecf20Sopenharmony_ci seg_hdr->data_offset = cpu_to_le32(sizeof(*seg_hdr)); 36268c2ecf20Sopenharmony_ci seg_hdr->instance = cpu_to_le32(instance); 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_cistatic void 36308c2ecf20Sopenharmony_cibnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, 36318c2ecf20Sopenharmony_ci time64_t start, s16 start_utc, u16 total_segs, 36328c2ecf20Sopenharmony_ci int status) 36338c2ecf20Sopenharmony_ci{ 36348c2ecf20Sopenharmony_ci time64_t end = ktime_get_real_seconds(); 36358c2ecf20Sopenharmony_ci u32 os_ver_major = 0, os_ver_minor = 0; 36368c2ecf20Sopenharmony_ci struct tm tm; 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci time64_to_tm(start, 0, &tm); 36398c2ecf20Sopenharmony_ci memset(record, 0, sizeof(*record)); 36408c2ecf20Sopenharmony_ci memcpy(record->signature, "cOrE", 4); 36418c2ecf20Sopenharmony_ci record->flags = 0; 36428c2ecf20Sopenharmony_ci record->low_version = 0; 36438c2ecf20Sopenharmony_ci record->high_version = 1; 36448c2ecf20Sopenharmony_ci record->asic_state = 0; 36458c2ecf20Sopenharmony_ci strlcpy(record->system_name, utsname()->nodename, 36468c2ecf20Sopenharmony_ci sizeof(record->system_name)); 36478c2ecf20Sopenharmony_ci record->year = cpu_to_le16(tm.tm_year + 1900); 36488c2ecf20Sopenharmony_ci record->month = cpu_to_le16(tm.tm_mon + 1); 36498c2ecf20Sopenharmony_ci record->day = cpu_to_le16(tm.tm_mday); 36508c2ecf20Sopenharmony_ci record->hour = cpu_to_le16(tm.tm_hour); 36518c2ecf20Sopenharmony_ci record->minute = cpu_to_le16(tm.tm_min); 36528c2ecf20Sopenharmony_ci record->second = cpu_to_le16(tm.tm_sec); 36538c2ecf20Sopenharmony_ci record->utc_bias = cpu_to_le16(start_utc); 36548c2ecf20Sopenharmony_ci strcpy(record->commandline, "ethtool -w"); 36558c2ecf20Sopenharmony_ci record->total_segments = cpu_to_le32(total_segs); 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci sscanf(utsname()->release, "%u.%u", &os_ver_major, &os_ver_minor); 36588c2ecf20Sopenharmony_ci record->os_ver_major = cpu_to_le32(os_ver_major); 36598c2ecf20Sopenharmony_ci record->os_ver_minor = cpu_to_le32(os_ver_minor); 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci strlcpy(record->os_name, utsname()->sysname, 32); 36628c2ecf20Sopenharmony_ci time64_to_tm(end, 0, &tm); 36638c2ecf20Sopenharmony_ci record->end_year = cpu_to_le16(tm.tm_year + 1900); 36648c2ecf20Sopenharmony_ci record->end_month = cpu_to_le16(tm.tm_mon + 1); 36658c2ecf20Sopenharmony_ci record->end_day = cpu_to_le16(tm.tm_mday); 36668c2ecf20Sopenharmony_ci record->end_hour = cpu_to_le16(tm.tm_hour); 36678c2ecf20Sopenharmony_ci record->end_minute = cpu_to_le16(tm.tm_min); 36688c2ecf20Sopenharmony_ci record->end_second = cpu_to_le16(tm.tm_sec); 36698c2ecf20Sopenharmony_ci record->end_utc_bias = cpu_to_le16(sys_tz.tz_minuteswest * 60); 36708c2ecf20Sopenharmony_ci record->asic_id1 = cpu_to_le32(bp->chip_num << 16 | 36718c2ecf20Sopenharmony_ci bp->ver_resp.chip_rev << 8 | 36728c2ecf20Sopenharmony_ci bp->ver_resp.chip_metal); 36738c2ecf20Sopenharmony_ci record->asic_id2 = 0; 36748c2ecf20Sopenharmony_ci record->coredump_status = cpu_to_le32(status); 36758c2ecf20Sopenharmony_ci record->ioctl_low_version = 0; 36768c2ecf20Sopenharmony_ci record->ioctl_high_version = 0; 36778c2ecf20Sopenharmony_ci} 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_cistatic int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) 36808c2ecf20Sopenharmony_ci{ 36818c2ecf20Sopenharmony_ci u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output); 36828c2ecf20Sopenharmony_ci u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0; 36838c2ecf20Sopenharmony_ci struct coredump_segment_record *seg_record = NULL; 36848c2ecf20Sopenharmony_ci struct bnxt_coredump_segment_hdr seg_hdr; 36858c2ecf20Sopenharmony_ci struct bnxt_coredump coredump = {NULL}; 36868c2ecf20Sopenharmony_ci time64_t start_time; 36878c2ecf20Sopenharmony_ci u16 start_utc; 36888c2ecf20Sopenharmony_ci int rc = 0, i; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci if (buf) 36918c2ecf20Sopenharmony_ci buf_len = *dump_len; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci start_time = ktime_get_real_seconds(); 36948c2ecf20Sopenharmony_ci start_utc = sys_tz.tz_minuteswest * 60; 36958c2ecf20Sopenharmony_ci seg_hdr_len = sizeof(seg_hdr); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci /* First segment should be hwrm_ver_get response */ 36988c2ecf20Sopenharmony_ci *dump_len = seg_hdr_len + ver_get_resp_len; 36998c2ecf20Sopenharmony_ci if (buf) { 37008c2ecf20Sopenharmony_ci bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, ver_get_resp_len, 37018c2ecf20Sopenharmony_ci 0, 0, 0); 37028c2ecf20Sopenharmony_ci memcpy(buf + offset, &seg_hdr, seg_hdr_len); 37038c2ecf20Sopenharmony_ci offset += seg_hdr_len; 37048c2ecf20Sopenharmony_ci memcpy(buf + offset, &bp->ver_resp, ver_get_resp_len); 37058c2ecf20Sopenharmony_ci offset += ver_get_resp_len; 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci rc = bnxt_hwrm_dbg_coredump_list(bp, &coredump); 37098c2ecf20Sopenharmony_ci if (rc) { 37108c2ecf20Sopenharmony_ci netdev_err(bp->dev, "Failed to get coredump segment list\n"); 37118c2ecf20Sopenharmony_ci goto err; 37128c2ecf20Sopenharmony_ci } 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci *dump_len += seg_hdr_len * coredump.total_segs; 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci seg_record = (struct coredump_segment_record *)coredump.data; 37178c2ecf20Sopenharmony_ci seg_record_len = sizeof(*seg_record); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci for (i = 0; i < coredump.total_segs; i++) { 37208c2ecf20Sopenharmony_ci u16 comp_id = le16_to_cpu(seg_record->component_id); 37218c2ecf20Sopenharmony_ci u16 seg_id = le16_to_cpu(seg_record->segment_id); 37228c2ecf20Sopenharmony_ci u32 duration = 0, seg_len = 0; 37238c2ecf20Sopenharmony_ci unsigned long start, end; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci if (buf && ((offset + seg_hdr_len) > 37268c2ecf20Sopenharmony_ci BNXT_COREDUMP_BUF_LEN(buf_len))) { 37278c2ecf20Sopenharmony_ci rc = -ENOBUFS; 37288c2ecf20Sopenharmony_ci goto err; 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci start = jiffies; 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id); 37348c2ecf20Sopenharmony_ci if (rc) { 37358c2ecf20Sopenharmony_ci netdev_err(bp->dev, 37368c2ecf20Sopenharmony_ci "Failed to initiate coredump for seg = %d\n", 37378c2ecf20Sopenharmony_ci seg_record->segment_id); 37388c2ecf20Sopenharmony_ci goto next_seg; 37398c2ecf20Sopenharmony_ci } 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci /* Write segment data into the buffer */ 37428c2ecf20Sopenharmony_ci rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id, 37438c2ecf20Sopenharmony_ci &seg_len, buf, buf_len, 37448c2ecf20Sopenharmony_ci offset + seg_hdr_len); 37458c2ecf20Sopenharmony_ci if (rc && rc == -ENOBUFS) 37468c2ecf20Sopenharmony_ci goto err; 37478c2ecf20Sopenharmony_ci else if (rc) 37488c2ecf20Sopenharmony_ci netdev_err(bp->dev, 37498c2ecf20Sopenharmony_ci "Failed to retrieve coredump for seg = %d\n", 37508c2ecf20Sopenharmony_ci seg_record->segment_id); 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_cinext_seg: 37538c2ecf20Sopenharmony_ci end = jiffies; 37548c2ecf20Sopenharmony_ci duration = jiffies_to_msecs(end - start); 37558c2ecf20Sopenharmony_ci bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, seg_record, seg_len, 37568c2ecf20Sopenharmony_ci rc, duration, 0); 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci if (buf) { 37598c2ecf20Sopenharmony_ci /* Write segment header into the buffer */ 37608c2ecf20Sopenharmony_ci memcpy(buf + offset, &seg_hdr, seg_hdr_len); 37618c2ecf20Sopenharmony_ci offset += seg_hdr_len + seg_len; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci *dump_len += seg_len; 37658c2ecf20Sopenharmony_ci seg_record = 37668c2ecf20Sopenharmony_ci (struct coredump_segment_record *)((u8 *)seg_record + 37678c2ecf20Sopenharmony_ci seg_record_len); 37688c2ecf20Sopenharmony_ci } 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_cierr: 37718c2ecf20Sopenharmony_ci if (buf) 37728c2ecf20Sopenharmony_ci bnxt_fill_coredump_record(bp, buf + offset, start_time, 37738c2ecf20Sopenharmony_ci start_utc, coredump.total_segs + 1, 37748c2ecf20Sopenharmony_ci rc); 37758c2ecf20Sopenharmony_ci kfree(coredump.data); 37768c2ecf20Sopenharmony_ci *dump_len += sizeof(struct bnxt_coredump_record); 37778c2ecf20Sopenharmony_ci if (rc == -ENOBUFS) 37788c2ecf20Sopenharmony_ci netdev_err(bp->dev, "Firmware returned large coredump buffer\n"); 37798c2ecf20Sopenharmony_ci return rc; 37808c2ecf20Sopenharmony_ci} 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_cistatic int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 37838c2ecf20Sopenharmony_ci{ 37848c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci if (dump->flag > BNXT_DUMP_CRASH) { 37878c2ecf20Sopenharmony_ci netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 37888c2ecf20Sopenharmony_ci return -EINVAL; 37898c2ecf20Sopenharmony_ci } 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 37928c2ecf20Sopenharmony_ci netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 37938c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 37948c2ecf20Sopenharmony_ci } 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci bp->dump_flag = dump->flag; 37978c2ecf20Sopenharmony_ci return 0; 37988c2ecf20Sopenharmony_ci} 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_cistatic int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 38018c2ecf20Sopenharmony_ci{ 38028c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code < 0x10801) 38058c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38068c2ecf20Sopenharmony_ci 38078c2ecf20Sopenharmony_ci dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 38088c2ecf20Sopenharmony_ci bp->ver_resp.hwrm_fw_min_8b << 16 | 38098c2ecf20Sopenharmony_ci bp->ver_resp.hwrm_fw_bld_8b << 8 | 38108c2ecf20Sopenharmony_ci bp->ver_resp.hwrm_fw_rsvd_8b; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci dump->flag = bp->dump_flag; 38138c2ecf20Sopenharmony_ci if (bp->dump_flag == BNXT_DUMP_CRASH) 38148c2ecf20Sopenharmony_ci dump->len = BNXT_CRASH_DUMP_LEN; 38158c2ecf20Sopenharmony_ci else 38168c2ecf20Sopenharmony_ci bnxt_get_coredump(bp, NULL, &dump->len); 38178c2ecf20Sopenharmony_ci return 0; 38188c2ecf20Sopenharmony_ci} 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_cistatic int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 38218c2ecf20Sopenharmony_ci void *buf) 38228c2ecf20Sopenharmony_ci{ 38238c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(dev); 38248c2ecf20Sopenharmony_ci 38258c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code < 0x10801) 38268c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci memset(buf, 0, dump->len); 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci dump->flag = bp->dump_flag; 38318c2ecf20Sopenharmony_ci if (dump->flag == BNXT_DUMP_CRASH) { 38328c2ecf20Sopenharmony_ci#ifdef CONFIG_TEE_BNXT_FW 38338c2ecf20Sopenharmony_ci return tee_bnxt_copy_coredump(buf, 0, dump->len); 38348c2ecf20Sopenharmony_ci#endif 38358c2ecf20Sopenharmony_ci } else { 38368c2ecf20Sopenharmony_ci return bnxt_get_coredump(bp, buf, &dump->len); 38378c2ecf20Sopenharmony_ci } 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_ci return 0; 38408c2ecf20Sopenharmony_ci} 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_civoid bnxt_ethtool_init(struct bnxt *bp) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr; 38458c2ecf20Sopenharmony_ci struct hwrm_selftest_qlist_input req = {0}; 38468c2ecf20Sopenharmony_ci struct bnxt_test_info *test_info; 38478c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 38488c2ecf20Sopenharmony_ci int i, rc; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 38518c2ecf20Sopenharmony_ci bnxt_get_pkgver(dev); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci bp->num_tests = 0; 38548c2ecf20Sopenharmony_ci if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 38558c2ecf20Sopenharmony_ci return; 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_QLIST, -1, -1); 38588c2ecf20Sopenharmony_ci mutex_lock(&bp->hwrm_cmd_lock); 38598c2ecf20Sopenharmony_ci rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 38608c2ecf20Sopenharmony_ci if (rc) 38618c2ecf20Sopenharmony_ci goto ethtool_init_exit; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci test_info = bp->test_info; 38648c2ecf20Sopenharmony_ci if (!test_info) 38658c2ecf20Sopenharmony_ci test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 38668c2ecf20Sopenharmony_ci if (!test_info) 38678c2ecf20Sopenharmony_ci goto ethtool_init_exit; 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci bp->test_info = test_info; 38708c2ecf20Sopenharmony_ci bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 38718c2ecf20Sopenharmony_ci if (bp->num_tests > BNXT_MAX_TEST) 38728c2ecf20Sopenharmony_ci bp->num_tests = BNXT_MAX_TEST; 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci test_info->offline_mask = resp->offline_tests; 38758c2ecf20Sopenharmony_ci test_info->timeout = le16_to_cpu(resp->test_timeout); 38768c2ecf20Sopenharmony_ci if (!test_info->timeout) 38778c2ecf20Sopenharmony_ci test_info->timeout = HWRM_CMD_TIMEOUT; 38788c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tests; i++) { 38798c2ecf20Sopenharmony_ci char *str = test_info->string[i]; 38808c2ecf20Sopenharmony_ci char *fw_str = resp->test0_name + i * 32; 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (i == BNXT_MACLPBK_TEST_IDX) { 38838c2ecf20Sopenharmony_ci strcpy(str, "Mac loopback test (offline)"); 38848c2ecf20Sopenharmony_ci } else if (i == BNXT_PHYLPBK_TEST_IDX) { 38858c2ecf20Sopenharmony_ci strcpy(str, "Phy loopback test (offline)"); 38868c2ecf20Sopenharmony_ci } else if (i == BNXT_EXTLPBK_TEST_IDX) { 38878c2ecf20Sopenharmony_ci strcpy(str, "Ext loopback test (offline)"); 38888c2ecf20Sopenharmony_ci } else if (i == BNXT_IRQ_TEST_IDX) { 38898c2ecf20Sopenharmony_ci strcpy(str, "Interrupt_test (offline)"); 38908c2ecf20Sopenharmony_ci } else { 38918c2ecf20Sopenharmony_ci strlcpy(str, fw_str, ETH_GSTRING_LEN); 38928c2ecf20Sopenharmony_ci strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); 38938c2ecf20Sopenharmony_ci if (test_info->offline_mask & (1 << i)) 38948c2ecf20Sopenharmony_ci strncat(str, " (offline)", 38958c2ecf20Sopenharmony_ci ETH_GSTRING_LEN - strlen(str)); 38968c2ecf20Sopenharmony_ci else 38978c2ecf20Sopenharmony_ci strncat(str, " (online)", 38988c2ecf20Sopenharmony_ci ETH_GSTRING_LEN - strlen(str)); 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ciethtool_init_exit: 39038c2ecf20Sopenharmony_ci mutex_unlock(&bp->hwrm_cmd_lock); 39048c2ecf20Sopenharmony_ci} 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_civoid bnxt_ethtool_free(struct bnxt *bp) 39078c2ecf20Sopenharmony_ci{ 39088c2ecf20Sopenharmony_ci kfree(bp->test_info); 39098c2ecf20Sopenharmony_ci bp->test_info = NULL; 39108c2ecf20Sopenharmony_ci} 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ciconst struct ethtool_ops bnxt_ethtool_ops = { 39138c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 39148c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 39158c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USECS_IRQ | 39168c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 39178c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS | 39188c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 39198c2ecf20Sopenharmony_ci .get_link_ksettings = bnxt_get_link_ksettings, 39208c2ecf20Sopenharmony_ci .set_link_ksettings = bnxt_set_link_ksettings, 39218c2ecf20Sopenharmony_ci .get_fecparam = bnxt_get_fecparam, 39228c2ecf20Sopenharmony_ci .set_fecparam = bnxt_set_fecparam, 39238c2ecf20Sopenharmony_ci .get_pause_stats = bnxt_get_pause_stats, 39248c2ecf20Sopenharmony_ci .get_pauseparam = bnxt_get_pauseparam, 39258c2ecf20Sopenharmony_ci .set_pauseparam = bnxt_set_pauseparam, 39268c2ecf20Sopenharmony_ci .get_drvinfo = bnxt_get_drvinfo, 39278c2ecf20Sopenharmony_ci .get_regs_len = bnxt_get_regs_len, 39288c2ecf20Sopenharmony_ci .get_regs = bnxt_get_regs, 39298c2ecf20Sopenharmony_ci .get_wol = bnxt_get_wol, 39308c2ecf20Sopenharmony_ci .set_wol = bnxt_set_wol, 39318c2ecf20Sopenharmony_ci .get_coalesce = bnxt_get_coalesce, 39328c2ecf20Sopenharmony_ci .set_coalesce = bnxt_set_coalesce, 39338c2ecf20Sopenharmony_ci .get_msglevel = bnxt_get_msglevel, 39348c2ecf20Sopenharmony_ci .set_msglevel = bnxt_set_msglevel, 39358c2ecf20Sopenharmony_ci .get_sset_count = bnxt_get_sset_count, 39368c2ecf20Sopenharmony_ci .get_strings = bnxt_get_strings, 39378c2ecf20Sopenharmony_ci .get_ethtool_stats = bnxt_get_ethtool_stats, 39388c2ecf20Sopenharmony_ci .set_ringparam = bnxt_set_ringparam, 39398c2ecf20Sopenharmony_ci .get_ringparam = bnxt_get_ringparam, 39408c2ecf20Sopenharmony_ci .get_channels = bnxt_get_channels, 39418c2ecf20Sopenharmony_ci .set_channels = bnxt_set_channels, 39428c2ecf20Sopenharmony_ci .get_rxnfc = bnxt_get_rxnfc, 39438c2ecf20Sopenharmony_ci .set_rxnfc = bnxt_set_rxnfc, 39448c2ecf20Sopenharmony_ci .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 39458c2ecf20Sopenharmony_ci .get_rxfh_key_size = bnxt_get_rxfh_key_size, 39468c2ecf20Sopenharmony_ci .get_rxfh = bnxt_get_rxfh, 39478c2ecf20Sopenharmony_ci .set_rxfh = bnxt_set_rxfh, 39488c2ecf20Sopenharmony_ci .flash_device = bnxt_flash_device, 39498c2ecf20Sopenharmony_ci .get_eeprom_len = bnxt_get_eeprom_len, 39508c2ecf20Sopenharmony_ci .get_eeprom = bnxt_get_eeprom, 39518c2ecf20Sopenharmony_ci .set_eeprom = bnxt_set_eeprom, 39528c2ecf20Sopenharmony_ci .get_link = bnxt_get_link, 39538c2ecf20Sopenharmony_ci .get_eee = bnxt_get_eee, 39548c2ecf20Sopenharmony_ci .set_eee = bnxt_set_eee, 39558c2ecf20Sopenharmony_ci .get_module_info = bnxt_get_module_info, 39568c2ecf20Sopenharmony_ci .get_module_eeprom = bnxt_get_module_eeprom, 39578c2ecf20Sopenharmony_ci .nway_reset = bnxt_nway_reset, 39588c2ecf20Sopenharmony_ci .set_phys_id = bnxt_set_phys_id, 39598c2ecf20Sopenharmony_ci .self_test = bnxt_self_test, 39608c2ecf20Sopenharmony_ci .reset = bnxt_reset, 39618c2ecf20Sopenharmony_ci .set_dump = bnxt_set_dump, 39628c2ecf20Sopenharmony_ci .get_dump_flag = bnxt_get_dump_flag, 39638c2ecf20Sopenharmony_ci .get_dump_data = bnxt_get_dump_data, 39648c2ecf20Sopenharmony_ci}; 3965