1c0c050c5SMichael Chan /* Broadcom NetXtreme-C/E network driver. 2c0c050c5SMichael Chan * 311f15ed3SMichael Chan * Copyright (c) 2014-2016 Broadcom Corporation 48e202366SMichael Chan * Copyright (c) 2016-2017 Broadcom Limited 5c0c050c5SMichael Chan * 6c0c050c5SMichael Chan * This program is free software; you can redistribute it and/or modify 7c0c050c5SMichael Chan * it under the terms of the GNU General Public License as published by 8c0c050c5SMichael Chan * the Free Software Foundation. 9c0c050c5SMichael Chan */ 10c0c050c5SMichael Chan 113ebf6f0aSRob Swindell #include <linux/ctype.h> 128ddc9aaaSMichael Chan #include <linux/stringify.h> 13c0c050c5SMichael Chan #include <linux/ethtool.h> 14b370517eSJakub Kicinski #include <linux/ethtool_netlink.h> 158b277589SMichael Chan #include <linux/linkmode.h> 16c0c050c5SMichael Chan #include <linux/interrupt.h> 17c0c050c5SMichael Chan #include <linux/pci.h> 18c0c050c5SMichael Chan #include <linux/etherdevice.h> 19c0c050c5SMichael Chan #include <linux/crc32.h> 20c0c050c5SMichael Chan #include <linux/firmware.h> 216c5657d0SVasundhara Volam #include <linux/utsname.h> 226c5657d0SVasundhara Volam #include <linux/time.h> 23118612d5SMichael Chan #include <linux/ptp_clock_kernel.h> 24118612d5SMichael Chan #include <linux/net_tstamp.h> 25118612d5SMichael Chan #include <linux/timecounter.h> 26c0c050c5SMichael Chan #include "bnxt_hsi.h" 27c0c050c5SMichael Chan #include "bnxt.h" 283c8c20dbSEdwin Peer #include "bnxt_hwrm.h" 296758f937SMichael Chan #include "bnxt_ulp.h" 30f7dc1ea6SMichael Chan #include "bnxt_xdp.h" 31118612d5SMichael Chan #include "bnxt_ptp.h" 32c0c050c5SMichael Chan #include "bnxt_ethtool.h" 33c0c050c5SMichael Chan #include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ 34c0c050c5SMichael Chan #include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ 356c5657d0SVasundhara Volam #include "bnxt_coredump.h" 36c0c050c5SMichael Chan 37c0c050c5SMichael Chan static u32 bnxt_get_msglevel(struct net_device *dev) 38c0c050c5SMichael Chan { 39c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 40c0c050c5SMichael Chan 41c0c050c5SMichael Chan return bp->msg_enable; 42c0c050c5SMichael Chan } 43c0c050c5SMichael Chan 44c0c050c5SMichael Chan static void bnxt_set_msglevel(struct net_device *dev, u32 value) 45c0c050c5SMichael Chan { 46c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 47c0c050c5SMichael Chan 48c0c050c5SMichael Chan bp->msg_enable = value; 49c0c050c5SMichael Chan } 50c0c050c5SMichael Chan 51c0c050c5SMichael Chan static int bnxt_get_coalesce(struct net_device *dev, 52f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 53f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 54f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 55c0c050c5SMichael Chan { 56c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 5718775aa8SMichael Chan struct bnxt_coal *hw_coal; 5818775aa8SMichael Chan u16 mult; 59c0c050c5SMichael Chan 60c0c050c5SMichael Chan memset(coal, 0, sizeof(*coal)); 61c0c050c5SMichael Chan 626a8788f2SAndy Gospodarek coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; 636a8788f2SAndy Gospodarek 6418775aa8SMichael Chan hw_coal = &bp->rx_coal; 6518775aa8SMichael Chan mult = hw_coal->bufs_per_record; 6618775aa8SMichael Chan coal->rx_coalesce_usecs = hw_coal->coal_ticks; 6718775aa8SMichael Chan coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; 6818775aa8SMichael Chan coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 6918775aa8SMichael Chan coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 703fcbdbd5SMichael Chan if (hw_coal->flags & 713fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 723fcbdbd5SMichael Chan kernel_coal->use_cqe_mode_rx = true; 73c0c050c5SMichael Chan 7418775aa8SMichael Chan hw_coal = &bp->tx_coal; 7518775aa8SMichael Chan mult = hw_coal->bufs_per_record; 7618775aa8SMichael Chan coal->tx_coalesce_usecs = hw_coal->coal_ticks; 7718775aa8SMichael Chan coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; 7818775aa8SMichael Chan coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 7918775aa8SMichael Chan coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 803fcbdbd5SMichael Chan if (hw_coal->flags & 813fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 823fcbdbd5SMichael Chan kernel_coal->use_cqe_mode_tx = true; 83dfc9c94aSMichael Chan 8451f30785SMichael Chan coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; 8551f30785SMichael Chan 86c0c050c5SMichael Chan return 0; 87c0c050c5SMichael Chan } 88c0c050c5SMichael Chan 89c0c050c5SMichael Chan static int bnxt_set_coalesce(struct net_device *dev, 90f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 91f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 92f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 93c0c050c5SMichael Chan { 94c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 9551f30785SMichael Chan bool update_stats = false; 9618775aa8SMichael Chan struct bnxt_coal *hw_coal; 97c0c050c5SMichael Chan int rc = 0; 9818775aa8SMichael Chan u16 mult; 99c0c050c5SMichael Chan 1006a8788f2SAndy Gospodarek if (coal->use_adaptive_rx_coalesce) { 1016a8788f2SAndy Gospodarek bp->flags |= BNXT_FLAG_DIM; 1026a8788f2SAndy Gospodarek } else { 1036a8788f2SAndy Gospodarek if (bp->flags & BNXT_FLAG_DIM) { 1046a8788f2SAndy Gospodarek bp->flags &= ~(BNXT_FLAG_DIM); 1056a8788f2SAndy Gospodarek goto reset_coalesce; 1066a8788f2SAndy Gospodarek } 1076a8788f2SAndy Gospodarek } 1086a8788f2SAndy Gospodarek 1093fcbdbd5SMichael Chan if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && 1103fcbdbd5SMichael Chan !(bp->coal_cap.cmpl_params & 1113fcbdbd5SMichael Chan RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) 1123fcbdbd5SMichael Chan return -EOPNOTSUPP; 1133fcbdbd5SMichael Chan 11418775aa8SMichael Chan hw_coal = &bp->rx_coal; 11518775aa8SMichael Chan mult = hw_coal->bufs_per_record; 11618775aa8SMichael Chan hw_coal->coal_ticks = coal->rx_coalesce_usecs; 11718775aa8SMichael Chan hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; 11818775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; 11918775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; 1203fcbdbd5SMichael Chan hw_coal->flags &= 1213fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1223fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_rx) 1233fcbdbd5SMichael Chan hw_coal->flags |= 1243fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 125c0c050c5SMichael Chan 126de4a10efSAndy Gospodarek hw_coal = &bp->tx_coal; 12718775aa8SMichael Chan mult = hw_coal->bufs_per_record; 12818775aa8SMichael Chan hw_coal->coal_ticks = coal->tx_coalesce_usecs; 12918775aa8SMichael Chan hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; 13018775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; 13118775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; 1323fcbdbd5SMichael Chan hw_coal->flags &= 1333fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1343fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_tx) 1353fcbdbd5SMichael Chan hw_coal->flags |= 1363fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 137dfc9c94aSMichael Chan 13851f30785SMichael Chan if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { 13951f30785SMichael Chan u32 stats_ticks = coal->stats_block_coalesce_usecs; 14051f30785SMichael Chan 141adcc331eSMichael Chan /* Allow 0, which means disable. */ 142adcc331eSMichael Chan if (stats_ticks) 14351f30785SMichael Chan stats_ticks = clamp_t(u32, stats_ticks, 14451f30785SMichael Chan BNXT_MIN_STATS_COAL_TICKS, 14551f30785SMichael Chan BNXT_MAX_STATS_COAL_TICKS); 14651f30785SMichael Chan stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); 14751f30785SMichael Chan bp->stats_coal_ticks = stats_ticks; 148e795892eSMichael Chan if (bp->stats_coal_ticks) 149e795892eSMichael Chan bp->current_interval = 150e795892eSMichael Chan bp->stats_coal_ticks * HZ / 1000000; 151e795892eSMichael Chan else 152e795892eSMichael Chan bp->current_interval = BNXT_TIMER_INTERVAL; 15351f30785SMichael Chan update_stats = true; 15451f30785SMichael Chan } 15551f30785SMichael Chan 1566a8788f2SAndy Gospodarek reset_coalesce: 15751f30785SMichael Chan if (netif_running(dev)) { 15851f30785SMichael Chan if (update_stats) { 15951f30785SMichael Chan rc = bnxt_close_nic(bp, true, false); 16051f30785SMichael Chan if (!rc) 16151f30785SMichael Chan rc = bnxt_open_nic(bp, true, false); 16251f30785SMichael Chan } else { 163c0c050c5SMichael Chan rc = bnxt_hwrm_set_coal(bp); 16451f30785SMichael Chan } 16551f30785SMichael Chan } 166c0c050c5SMichael Chan 167c0c050c5SMichael Chan return rc; 168c0c050c5SMichael Chan } 169c0c050c5SMichael Chan 1703316d509SMichael Chan static const char * const bnxt_ring_rx_stats_str[] = { 171ee79566eSMichael Chan "rx_ucast_packets", 172ee79566eSMichael Chan "rx_mcast_packets", 173ee79566eSMichael Chan "rx_bcast_packets", 174ee79566eSMichael Chan "rx_discards", 175bfc6e5fbSMichael Chan "rx_errors", 176ee79566eSMichael Chan "rx_ucast_bytes", 177ee79566eSMichael Chan "rx_mcast_bytes", 178ee79566eSMichael Chan "rx_bcast_bytes", 1793316d509SMichael Chan }; 1803316d509SMichael Chan 1813316d509SMichael Chan static const char * const bnxt_ring_tx_stats_str[] = { 182ee79566eSMichael Chan "tx_ucast_packets", 183ee79566eSMichael Chan "tx_mcast_packets", 184ee79566eSMichael Chan "tx_bcast_packets", 185bfc6e5fbSMichael Chan "tx_errors", 186ee79566eSMichael Chan "tx_discards", 187ee79566eSMichael Chan "tx_ucast_bytes", 188ee79566eSMichael Chan "tx_mcast_bytes", 189ee79566eSMichael Chan "tx_bcast_bytes", 190ee79566eSMichael Chan }; 191ee79566eSMichael Chan 192ee79566eSMichael Chan static const char * const bnxt_ring_tpa_stats_str[] = { 193ee79566eSMichael Chan "tpa_packets", 194ee79566eSMichael Chan "tpa_bytes", 195ee79566eSMichael Chan "tpa_events", 196ee79566eSMichael Chan "tpa_aborts", 197ee79566eSMichael Chan }; 198ee79566eSMichael Chan 19978e7b866SMichael Chan static const char * const bnxt_ring_tpa2_stats_str[] = { 20078e7b866SMichael Chan "rx_tpa_eligible_pkt", 20178e7b866SMichael Chan "rx_tpa_eligible_bytes", 20278e7b866SMichael Chan "rx_tpa_pkt", 20378e7b866SMichael Chan "rx_tpa_bytes", 20478e7b866SMichael Chan "rx_tpa_errors", 2059d6b648cSMichael Chan "rx_tpa_events", 20678e7b866SMichael Chan }; 20778e7b866SMichael Chan 2089d8b5f05SMichael Chan static const char * const bnxt_rx_sw_stats_str[] = { 209ee79566eSMichael Chan "rx_l4_csum_errors", 2108a27d4b9SMichael Chan "rx_resets", 21119b3751fSMichael Chan "rx_buf_errors", 2129d8b5f05SMichael Chan }; 2139d8b5f05SMichael Chan 2149d8b5f05SMichael Chan static const char * const bnxt_cmn_sw_stats_str[] = { 215ee79566eSMichael Chan "missed_irqs", 216ee79566eSMichael Chan }; 217c0c050c5SMichael Chan 2188ddc9aaaSMichael Chan #define BNXT_RX_STATS_ENTRY(counter) \ 2198ddc9aaaSMichael Chan { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } 2208ddc9aaaSMichael Chan 2218ddc9aaaSMichael Chan #define BNXT_TX_STATS_ENTRY(counter) \ 2228ddc9aaaSMichael Chan { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } 2238ddc9aaaSMichael Chan 22400db3cbaSVasundhara Volam #define BNXT_RX_STATS_EXT_ENTRY(counter) \ 22500db3cbaSVasundhara Volam { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } 22600db3cbaSVasundhara Volam 22736e53349SMichael Chan #define BNXT_TX_STATS_EXT_ENTRY(counter) \ 22836e53349SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } 22936e53349SMichael Chan 23036e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ 23136e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ 23236e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) 23336e53349SMichael Chan 23436e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ 23536e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ 23636e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) 23736e53349SMichael Chan 23836e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRIES \ 23936e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ 24036e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ 24136e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ 24236e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ 24336e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ 24436e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ 24536e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ 24636e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(7) 24736e53349SMichael Chan 24836e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRIES \ 24936e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ 25036e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ 25136e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ 25236e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ 25336e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ 25436e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ 25536e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ 25636e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(7) 25736e53349SMichael Chan 25836e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ 25936e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ 26036e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) 26136e53349SMichael Chan 26236e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ 26336e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ 26436e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) 26536e53349SMichael Chan 26636e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRIES \ 26736e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(0), \ 26836e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(1), \ 26936e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(2), \ 27036e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(3), \ 27136e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(4), \ 27236e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(5), \ 27336e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(6), \ 27436e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(7) \ 27536e53349SMichael Chan 27636e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRIES \ 27736e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(0), \ 27836e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(1), \ 27936e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(2), \ 28036e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(3), \ 28136e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(4), \ 28236e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(5), \ 28336e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(6), \ 28436e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(7) \ 28536e53349SMichael Chan 2862792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ 2872792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ 2882792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) 2892792b5b9SMichael Chan 2902792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ 2912792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ 2922792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ 2932792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ 2942792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ 2952792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ 2962792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ 2972792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ 2982792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) 2992792b5b9SMichael Chan 300e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ 301e37fed79SMichael Chan { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ 302e37fed79SMichael Chan __stringify(counter##_pri##n) } 303e37fed79SMichael Chan 304e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ 305e37fed79SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ 306e37fed79SMichael Chan __stringify(counter##_pri##n) } 307e37fed79SMichael Chan 308e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRIES(counter) \ 309e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ 310e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ 311e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ 312e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ 313e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ 314e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ 315e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ 316e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 7) 317e37fed79SMichael Chan 318e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRIES(counter) \ 319e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ 320e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ 321e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ 322e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ 323e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ 324e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ 325e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ 326e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 7) 327e37fed79SMichael Chan 32820c1d28eSVasundhara Volam enum { 32920c1d28eSVasundhara Volam RX_TOTAL_DISCARDS, 33020c1d28eSVasundhara Volam TX_TOTAL_DISCARDS, 33140bedf7cSJakub Kicinski RX_NETPOLL_DISCARDS, 33220c1d28eSVasundhara Volam }; 33320c1d28eSVasundhara Volam 33420c1d28eSVasundhara Volam static struct { 33520c1d28eSVasundhara Volam u64 counter; 33620c1d28eSVasundhara Volam char string[ETH_GSTRING_LEN]; 33720c1d28eSVasundhara Volam } bnxt_sw_func_stats[] = { 33820c1d28eSVasundhara Volam {0, "rx_total_discard_pkts"}, 33920c1d28eSVasundhara Volam {0, "tx_total_discard_pkts"}, 34040bedf7cSJakub Kicinski {0, "rx_total_netpoll_discards"}, 34120c1d28eSVasundhara Volam }; 34220c1d28eSVasundhara Volam 3433316d509SMichael Chan #define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) 3443316d509SMichael Chan #define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) 3453316d509SMichael Chan #define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) 3463316d509SMichael Chan #define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) 3473316d509SMichael Chan 3488ddc9aaaSMichael Chan static const struct { 3498ddc9aaaSMichael Chan long offset; 3508ddc9aaaSMichael Chan char string[ETH_GSTRING_LEN]; 3518ddc9aaaSMichael Chan } bnxt_port_stats_arr[] = { 3528ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_64b_frames), 3538ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), 3548ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), 3558ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), 3568ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), 3576fc92c33SMichael Chan BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), 3588ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), 3598ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), 3608ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), 3618ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), 3628ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), 3638ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_total_frames), 3648ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ucast_frames), 3658ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mcast_frames), 3668ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bcast_frames), 3678ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), 3688ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ctrl_frames), 3698ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pause_frames), 3708ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_frames), 3718ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_align_err_frames), 3728ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), 3738ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_jbr_frames), 3748ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), 3758ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_tagged_frames), 3768ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), 3778ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_frames), 378c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), 379c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), 380c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), 381c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), 382c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), 383c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), 384c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), 385c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), 3868ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_undrsz_frames), 3878ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), 3888ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), 3898ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bytes), 3908ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_bytes), 3918ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_frames), 392699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_discard), 393699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_err), 3948ddc9aaaSMichael Chan 3958ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_64b_frames), 3968ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), 3978ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), 3988ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), 3998ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), 4006fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), 4018ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), 4026fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), 4038ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), 4048ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), 4058ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), 4068ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_frames), 4078ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_frames), 4088ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_ucast_frames), 4098ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_mcast_frames), 4108ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bcast_frames), 4118ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pause_frames), 4128ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_frames), 4138ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_jabber_frames), 4148ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), 4158ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_err), 4168ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fifo_underruns), 417c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), 418c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), 419c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), 420c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), 421c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), 422c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), 423c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), 424c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), 4258ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), 4268ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), 4278ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_collisions), 4288ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bytes), 429699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_xthol_frames), 430699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_discard), 431699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_error), 4328ddc9aaaSMichael Chan }; 4338ddc9aaaSMichael Chan 43400db3cbaSVasundhara Volam static const struct { 43500db3cbaSVasundhara Volam long offset; 43600db3cbaSVasundhara Volam char string[ETH_GSTRING_LEN]; 43700db3cbaSVasundhara Volam } bnxt_port_stats_ext_arr[] = { 43800db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(link_down_events), 43900db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), 44000db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), 44100db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), 44200db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), 44336e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRIES, 44436e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRIES, 4454a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bits), 4464a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), 4474a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), 4484a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), 4492792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, 45021e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), 45121e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), 45236e53349SMichael Chan }; 45336e53349SMichael Chan 45436e53349SMichael Chan static const struct { 45536e53349SMichael Chan long offset; 45636e53349SMichael Chan char string[ETH_GSTRING_LEN]; 45736e53349SMichael Chan } bnxt_tx_port_stats_ext_arr[] = { 45836e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRIES, 45936e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRIES, 46000db3cbaSVasundhara Volam }; 46100db3cbaSVasundhara Volam 462e37fed79SMichael Chan static const struct { 463e37fed79SMichael Chan long base_off; 464e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 465e37fed79SMichael Chan } bnxt_rx_bytes_pri_arr[] = { 466e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), 467e37fed79SMichael Chan }; 468e37fed79SMichael Chan 469e37fed79SMichael Chan static const struct { 470e37fed79SMichael Chan long base_off; 471e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 472e37fed79SMichael Chan } bnxt_rx_pkts_pri_arr[] = { 473e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_packets), 474e37fed79SMichael Chan }; 475e37fed79SMichael Chan 476e37fed79SMichael Chan static const struct { 477e37fed79SMichael Chan long base_off; 478e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 479e37fed79SMichael Chan } bnxt_tx_bytes_pri_arr[] = { 480e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), 481e37fed79SMichael Chan }; 482e37fed79SMichael Chan 483e37fed79SMichael Chan static const struct { 484e37fed79SMichael Chan long base_off; 485e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 486e37fed79SMichael Chan } bnxt_tx_pkts_pri_arr[] = { 487e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_packets), 488e37fed79SMichael Chan }; 489e37fed79SMichael Chan 49020c1d28eSVasundhara Volam #define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats) 4918ddc9aaaSMichael Chan #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) 492e37fed79SMichael Chan #define BNXT_NUM_STATS_PRI \ 493e37fed79SMichael Chan (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ 494e37fed79SMichael Chan ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ 495e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ 496e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) 4978ddc9aaaSMichael Chan 49878e7b866SMichael Chan static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) 49978e7b866SMichael Chan { 50078e7b866SMichael Chan if (BNXT_SUPPORTS_TPA(bp)) { 5019d6b648cSMichael Chan if (bp->max_tpa_v2) { 5029d6b648cSMichael Chan if (BNXT_CHIP_P5_THOR(bp)) 5039d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5; 5049d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5_SR2; 5059d6b648cSMichael Chan } 5069d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS; 50778e7b866SMichael Chan } 50878e7b866SMichael Chan return 0; 50978e7b866SMichael Chan } 51078e7b866SMichael Chan 511ee79566eSMichael Chan static int bnxt_get_num_ring_stats(struct bnxt *bp) 512ee79566eSMichael Chan { 5133316d509SMichael Chan int rx, tx, cmn; 514ee79566eSMichael Chan 5153316d509SMichael Chan rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + 51678e7b866SMichael Chan bnxt_get_num_tpa_ring_stats(bp); 5173316d509SMichael Chan tx = NUM_RING_TX_HW_STATS; 5183316d509SMichael Chan cmn = NUM_RING_CMN_SW_STATS; 519125592fbSRajesh Ravi return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + 520125592fbSRajesh Ravi cmn * bp->cp_nr_rings; 521ee79566eSMichael Chan } 522ee79566eSMichael Chan 5235c8227d0SMichael Chan static int bnxt_get_num_stats(struct bnxt *bp) 524c0c050c5SMichael Chan { 525ee79566eSMichael Chan int num_stats = bnxt_get_num_ring_stats(bp); 5268ddc9aaaSMichael Chan 52720c1d28eSVasundhara Volam num_stats += BNXT_NUM_SW_FUNC_STATS; 52820c1d28eSVasundhara Volam 5298ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) 5308ddc9aaaSMichael Chan num_stats += BNXT_NUM_PORT_STATS; 5318ddc9aaaSMichael Chan 532e37fed79SMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 53336e53349SMichael Chan num_stats += bp->fw_rx_stats_ext_size + 53436e53349SMichael Chan bp->fw_tx_stats_ext_size; 535e37fed79SMichael Chan if (bp->pri2cos_valid) 536e37fed79SMichael Chan num_stats += BNXT_NUM_STATS_PRI; 537e37fed79SMichael Chan } 53800db3cbaSVasundhara Volam 5398ddc9aaaSMichael Chan return num_stats; 5408ddc9aaaSMichael Chan } 5415c8227d0SMichael Chan 5425c8227d0SMichael Chan static int bnxt_get_sset_count(struct net_device *dev, int sset) 5435c8227d0SMichael Chan { 5445c8227d0SMichael Chan struct bnxt *bp = netdev_priv(dev); 5455c8227d0SMichael Chan 5465c8227d0SMichael Chan switch (sset) { 5475c8227d0SMichael Chan case ETH_SS_STATS: 5485c8227d0SMichael Chan return bnxt_get_num_stats(bp); 549eb513658SMichael Chan case ETH_SS_TEST: 550eb513658SMichael Chan if (!bp->num_tests) 551eb513658SMichael Chan return -EOPNOTSUPP; 552eb513658SMichael Chan return bp->num_tests; 553c0c050c5SMichael Chan default: 554c0c050c5SMichael Chan return -EOPNOTSUPP; 555c0c050c5SMichael Chan } 556c0c050c5SMichael Chan } 557c0c050c5SMichael Chan 558125592fbSRajesh Ravi static bool is_rx_ring(struct bnxt *bp, int ring_num) 559125592fbSRajesh Ravi { 560125592fbSRajesh Ravi return ring_num < bp->rx_nr_rings; 561125592fbSRajesh Ravi } 562125592fbSRajesh Ravi 563125592fbSRajesh Ravi static bool is_tx_ring(struct bnxt *bp, int ring_num) 564125592fbSRajesh Ravi { 565125592fbSRajesh Ravi int tx_base = 0; 566125592fbSRajesh Ravi 567125592fbSRajesh Ravi if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) 568125592fbSRajesh Ravi tx_base = bp->rx_nr_rings; 569125592fbSRajesh Ravi 570125592fbSRajesh Ravi if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) 571125592fbSRajesh Ravi return true; 572125592fbSRajesh Ravi return false; 573125592fbSRajesh Ravi } 574125592fbSRajesh Ravi 575c0c050c5SMichael Chan static void bnxt_get_ethtool_stats(struct net_device *dev, 576c0c050c5SMichael Chan struct ethtool_stats *stats, u64 *buf) 577c0c050c5SMichael Chan { 578c0c050c5SMichael Chan u32 i, j = 0; 579c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 580125592fbSRajesh Ravi u32 tpa_stats; 581c0c050c5SMichael Chan 582fd3ab1c7SMichael Chan if (!bp->bnapi) { 583ee79566eSMichael Chan j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS; 584fd3ab1c7SMichael Chan goto skip_ring_stats; 585fd3ab1c7SMichael Chan } 586c0c050c5SMichael Chan 58720c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) 58820c1d28eSVasundhara Volam bnxt_sw_func_stats[i].counter = 0; 58920c1d28eSVasundhara Volam 590125592fbSRajesh Ravi tpa_stats = bnxt_get_num_tpa_ring_stats(bp); 591c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 592c0c050c5SMichael Chan struct bnxt_napi *bnapi = bp->bnapi[i]; 593c0c050c5SMichael Chan struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; 594a0c30621SMichael Chan u64 *sw_stats = cpr->stats.sw_stats; 5959d8b5f05SMichael Chan u64 *sw; 596c0c050c5SMichael Chan int k; 597c0c050c5SMichael Chan 598125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 599125592fbSRajesh Ravi for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) 600a0c30621SMichael Chan buf[j] = sw_stats[k]; 601125592fbSRajesh Ravi } 602125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 603125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS; 604125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 605125592fbSRajesh Ravi j++, k++) 606a0c30621SMichael Chan buf[j] = sw_stats[k]; 607125592fbSRajesh Ravi } 608125592fbSRajesh Ravi if (!tpa_stats || !is_rx_ring(bp, i)) 609125592fbSRajesh Ravi goto skip_tpa_ring_stats; 610125592fbSRajesh Ravi 611125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 612125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + 613125592fbSRajesh Ravi tpa_stats; j++, k++) 614a0c30621SMichael Chan buf[j] = sw_stats[k]; 6159d8b5f05SMichael Chan 616125592fbSRajesh Ravi skip_tpa_ring_stats: 6179d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.rx; 618125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 6193316d509SMichael Chan for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) 6209d8b5f05SMichael Chan buf[j] = sw[k]; 621125592fbSRajesh Ravi } 6229d8b5f05SMichael Chan 6239d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.cmn; 6243316d509SMichael Chan for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) 6259d8b5f05SMichael Chan buf[j] = sw[k]; 62620c1d28eSVasundhara Volam 62720c1d28eSVasundhara Volam bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += 628a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts); 62920c1d28eSVasundhara Volam bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter += 630a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts); 63140bedf7cSJakub Kicinski bnxt_sw_func_stats[RX_NETPOLL_DISCARDS].counter += 63240bedf7cSJakub Kicinski cpr->sw_stats.rx.rx_netpoll_discards; 633c0c050c5SMichael Chan } 63420c1d28eSVasundhara Volam 63520c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++) 63620c1d28eSVasundhara Volam buf[j] = bnxt_sw_func_stats[i].counter; 63720c1d28eSVasundhara Volam 638fd3ab1c7SMichael Chan skip_ring_stats: 6398ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 640a0c30621SMichael Chan u64 *port_stats = bp->port_stats.sw_stats; 6418ddc9aaaSMichael Chan 642a0c30621SMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) 643a0c30621SMichael Chan buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); 6448ddc9aaaSMichael Chan } 64500db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 646a0c30621SMichael Chan u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; 647a0c30621SMichael Chan u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; 64800db3cbaSVasundhara Volam 64936e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { 650a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + 651a0c30621SMichael Chan bnxt_port_stats_ext_arr[i].offset); 65200db3cbaSVasundhara Volam } 65336e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { 654a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + 655a0c30621SMichael Chan bnxt_tx_port_stats_ext_arr[i].offset); 65636e53349SMichael Chan } 657e37fed79SMichael Chan if (bp->pri2cos_valid) { 658e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 659e37fed79SMichael Chan long n = bnxt_rx_bytes_pri_arr[i].base_off + 660a24ec322SMichael Chan bp->pri2cos_idx[i]; 661e37fed79SMichael Chan 662a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 663e37fed79SMichael Chan } 664e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 665e37fed79SMichael Chan long n = bnxt_rx_pkts_pri_arr[i].base_off + 666a24ec322SMichael Chan bp->pri2cos_idx[i]; 667e37fed79SMichael Chan 668a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 669e37fed79SMichael Chan } 670e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 671e37fed79SMichael Chan long n = bnxt_tx_bytes_pri_arr[i].base_off + 672a24ec322SMichael Chan bp->pri2cos_idx[i]; 673e37fed79SMichael Chan 674a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 675e37fed79SMichael Chan } 676e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 677e37fed79SMichael Chan long n = bnxt_tx_pkts_pri_arr[i].base_off + 678a24ec322SMichael Chan bp->pri2cos_idx[i]; 679e37fed79SMichael Chan 680a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 681e37fed79SMichael Chan } 682e37fed79SMichael Chan } 68300db3cbaSVasundhara Volam } 684c0c050c5SMichael Chan } 685c0c050c5SMichael Chan 686c0c050c5SMichael Chan static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 687c0c050c5SMichael Chan { 688c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 68978e7b866SMichael Chan static const char * const *str; 690ee79566eSMichael Chan u32 i, j, num_str; 691c0c050c5SMichael Chan 692c0c050c5SMichael Chan switch (stringset) { 693c0c050c5SMichael Chan case ETH_SS_STATS: 694c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 695125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 6963316d509SMichael Chan num_str = NUM_RING_RX_HW_STATS; 697ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 698ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 6993316d509SMichael Chan bnxt_ring_rx_stats_str[j]); 700c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 701ee79566eSMichael Chan } 702125592fbSRajesh Ravi } 703125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 7043316d509SMichael Chan num_str = NUM_RING_TX_HW_STATS; 7053316d509SMichael Chan for (j = 0; j < num_str; j++) { 7063316d509SMichael Chan sprintf(buf, "[%d]: %s", i, 7073316d509SMichael Chan bnxt_ring_tx_stats_str[j]); 7083316d509SMichael Chan buf += ETH_GSTRING_LEN; 7093316d509SMichael Chan } 710125592fbSRajesh Ravi } 7113316d509SMichael Chan num_str = bnxt_get_num_tpa_ring_stats(bp); 712125592fbSRajesh Ravi if (!num_str || !is_rx_ring(bp, i)) 713ee79566eSMichael Chan goto skip_tpa_stats; 714ee79566eSMichael Chan 7153316d509SMichael Chan if (bp->max_tpa_v2) 71678e7b866SMichael Chan str = bnxt_ring_tpa2_stats_str; 7173316d509SMichael Chan else 71878e7b866SMichael Chan str = bnxt_ring_tpa_stats_str; 7193316d509SMichael Chan 720ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 72178e7b866SMichael Chan sprintf(buf, "[%d]: %s", i, str[j]); 722c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 723ee79566eSMichael Chan } 724ee79566eSMichael Chan skip_tpa_stats: 725125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 7263316d509SMichael Chan num_str = NUM_RING_RX_SW_STATS; 727ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 728ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 7299d8b5f05SMichael Chan bnxt_rx_sw_stats_str[j]); 7309d8b5f05SMichael Chan buf += ETH_GSTRING_LEN; 7319d8b5f05SMichael Chan } 732125592fbSRajesh Ravi } 7333316d509SMichael Chan num_str = NUM_RING_CMN_SW_STATS; 7349d8b5f05SMichael Chan for (j = 0; j < num_str; j++) { 7359d8b5f05SMichael Chan sprintf(buf, "[%d]: %s", i, 7369d8b5f05SMichael Chan bnxt_cmn_sw_stats_str[j]); 737c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 738ee79566eSMichael Chan } 739c0c050c5SMichael Chan } 74020c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) { 74120c1d28eSVasundhara Volam strcpy(buf, bnxt_sw_func_stats[i].string); 74220c1d28eSVasundhara Volam buf += ETH_GSTRING_LEN; 74320c1d28eSVasundhara Volam } 74420c1d28eSVasundhara Volam 7458ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 7468ddc9aaaSMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { 7478ddc9aaaSMichael Chan strcpy(buf, bnxt_port_stats_arr[i].string); 7488ddc9aaaSMichael Chan buf += ETH_GSTRING_LEN; 7498ddc9aaaSMichael Chan } 7508ddc9aaaSMichael Chan } 75100db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 75236e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { 75300db3cbaSVasundhara Volam strcpy(buf, bnxt_port_stats_ext_arr[i].string); 75400db3cbaSVasundhara Volam buf += ETH_GSTRING_LEN; 75500db3cbaSVasundhara Volam } 75636e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { 75736e53349SMichael Chan strcpy(buf, 75836e53349SMichael Chan bnxt_tx_port_stats_ext_arr[i].string); 75936e53349SMichael Chan buf += ETH_GSTRING_LEN; 76036e53349SMichael Chan } 761e37fed79SMichael Chan if (bp->pri2cos_valid) { 762e37fed79SMichael Chan for (i = 0; i < 8; i++) { 763e37fed79SMichael Chan strcpy(buf, 764e37fed79SMichael Chan bnxt_rx_bytes_pri_arr[i].string); 765e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 766e37fed79SMichael Chan } 767e37fed79SMichael Chan for (i = 0; i < 8; i++) { 768e37fed79SMichael Chan strcpy(buf, 769e37fed79SMichael Chan bnxt_rx_pkts_pri_arr[i].string); 770e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 771e37fed79SMichael Chan } 772e37fed79SMichael Chan for (i = 0; i < 8; i++) { 773e37fed79SMichael Chan strcpy(buf, 774e37fed79SMichael Chan bnxt_tx_bytes_pri_arr[i].string); 775e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 776e37fed79SMichael Chan } 777e37fed79SMichael Chan for (i = 0; i < 8; i++) { 778e37fed79SMichael Chan strcpy(buf, 779e37fed79SMichael Chan bnxt_tx_pkts_pri_arr[i].string); 780e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 781e37fed79SMichael Chan } 782e37fed79SMichael Chan } 78300db3cbaSVasundhara Volam } 784c0c050c5SMichael Chan break; 785eb513658SMichael Chan case ETH_SS_TEST: 786eb513658SMichael Chan if (bp->num_tests) 787eb513658SMichael Chan memcpy(buf, bp->test_info->string, 788eb513658SMichael Chan bp->num_tests * ETH_GSTRING_LEN); 789eb513658SMichael Chan break; 790c0c050c5SMichael Chan default: 791c0c050c5SMichael Chan netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", 792c0c050c5SMichael Chan stringset); 793c0c050c5SMichael Chan break; 794c0c050c5SMichael Chan } 795c0c050c5SMichael Chan } 796c0c050c5SMichael Chan 797c0c050c5SMichael Chan static void bnxt_get_ringparam(struct net_device *dev, 79874624944SHao Chen struct ethtool_ringparam *ering, 79974624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 80074624944SHao Chen struct netlink_ext_ack *extack) 801c0c050c5SMichael Chan { 802c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 803c0c050c5SMichael Chan 804c1129b51SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) { 805c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA; 806c0c050c5SMichael Chan ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; 807b370517eSJakub Kicinski kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; 808c1129b51SMichael Chan } else { 809c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; 810c1129b51SMichael Chan ering->rx_jumbo_max_pending = 0; 811b370517eSJakub Kicinski kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED; 812c1129b51SMichael Chan } 813c0c050c5SMichael Chan ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; 814c0c050c5SMichael Chan 815c0c050c5SMichael Chan ering->rx_pending = bp->rx_ring_size; 816c0c050c5SMichael Chan ering->rx_jumbo_pending = bp->rx_agg_ring_size; 817c0c050c5SMichael Chan ering->tx_pending = bp->tx_ring_size; 818c0c050c5SMichael Chan } 819c0c050c5SMichael Chan 820c0c050c5SMichael Chan static int bnxt_set_ringparam(struct net_device *dev, 82174624944SHao Chen struct ethtool_ringparam *ering, 82274624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 82374624944SHao Chen struct netlink_ext_ack *extack) 824c0c050c5SMichael Chan { 825c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 826c0c050c5SMichael Chan 827c0c050c5SMichael Chan if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || 828c0c050c5SMichael Chan (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || 8295bed8b07SMichael Chan (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) 830c0c050c5SMichael Chan return -EINVAL; 831c0c050c5SMichael Chan 832c0c050c5SMichael Chan if (netif_running(dev)) 833c0c050c5SMichael Chan bnxt_close_nic(bp, false, false); 834c0c050c5SMichael Chan 835c0c050c5SMichael Chan bp->rx_ring_size = ering->rx_pending; 836c0c050c5SMichael Chan bp->tx_ring_size = ering->tx_pending; 837c0c050c5SMichael Chan bnxt_set_ring_params(bp); 838c0c050c5SMichael Chan 839c0c050c5SMichael Chan if (netif_running(dev)) 840c0c050c5SMichael Chan return bnxt_open_nic(bp, false, false); 841c0c050c5SMichael Chan 842c0c050c5SMichael Chan return 0; 843c0c050c5SMichael Chan } 844c0c050c5SMichael Chan 845c0c050c5SMichael Chan static void bnxt_get_channels(struct net_device *dev, 846c0c050c5SMichael Chan struct ethtool_channels *channel) 847c0c050c5SMichael Chan { 848c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 849db4723b3SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 850c0c050c5SMichael Chan int max_rx_rings, max_tx_rings, tcs; 8514301304bSMichael Chan int max_tx_sch_inputs, tx_grps; 852db4723b3SMichael Chan 853db4723b3SMichael Chan /* Get the most up-to-date max_tx_sch_inputs. */ 854c1c2d774SPavan Chebbi if (netif_running(dev) && BNXT_NEW_RM(bp)) 855db4723b3SMichael Chan bnxt_hwrm_func_resc_qcaps(bp, false); 856db4723b3SMichael Chan max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; 857c0c050c5SMichael Chan 8586e6c5a57SMichael Chan bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); 859db4723b3SMichael Chan if (max_tx_sch_inputs) 860db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 8614301304bSMichael Chan 8624301304bSMichael Chan tcs = netdev_get_num_tc(dev); 8634301304bSMichael Chan tx_grps = max(tcs, 1); 8644301304bSMichael Chan if (bp->tx_nr_rings_xdp) 8654301304bSMichael Chan tx_grps++; 8664301304bSMichael Chan max_tx_rings /= tx_grps; 867a79a5276SMichael Chan channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); 868068c9ec6SMichael Chan 86918d6e4e2SSatish Baddipadige if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { 87018d6e4e2SSatish Baddipadige max_rx_rings = 0; 87118d6e4e2SSatish Baddipadige max_tx_rings = 0; 87218d6e4e2SSatish Baddipadige } 873db4723b3SMichael Chan if (max_tx_sch_inputs) 874db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 87518d6e4e2SSatish Baddipadige 876c0c050c5SMichael Chan if (tcs > 1) 877c0c050c5SMichael Chan max_tx_rings /= tcs; 878c0c050c5SMichael Chan 879c0c050c5SMichael Chan channel->max_rx = max_rx_rings; 880c0c050c5SMichael Chan channel->max_tx = max_tx_rings; 881c0c050c5SMichael Chan channel->max_other = 0; 882068c9ec6SMichael Chan if (bp->flags & BNXT_FLAG_SHARED_RINGS) { 883068c9ec6SMichael Chan channel->combined_count = bp->rx_nr_rings; 88476595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp)) 88576595193SPrashant Sreedharan channel->combined_count--; 886068c9ec6SMichael Chan } else { 88776595193SPrashant Sreedharan if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { 888c0c050c5SMichael Chan channel->rx_count = bp->rx_nr_rings; 889c0c050c5SMichael Chan channel->tx_count = bp->tx_nr_rings_per_tc; 890c0c050c5SMichael Chan } 891068c9ec6SMichael Chan } 89276595193SPrashant Sreedharan } 893c0c050c5SMichael Chan 894c0c050c5SMichael Chan static int bnxt_set_channels(struct net_device *dev, 895c0c050c5SMichael Chan struct ethtool_channels *channel) 896c0c050c5SMichael Chan { 897c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 898d1e7925eSMichael Chan int req_tx_rings, req_rx_rings, tcs; 899068c9ec6SMichael Chan bool sh = false; 9005f449249SMichael Chan int tx_xdp = 0; 901d1e7925eSMichael Chan int rc = 0; 902c0c050c5SMichael Chan 903068c9ec6SMichael Chan if (channel->other_count) 904c0c050c5SMichael Chan return -EINVAL; 905c0c050c5SMichael Chan 906068c9ec6SMichael Chan if (!channel->combined_count && 907068c9ec6SMichael Chan (!channel->rx_count || !channel->tx_count)) 908068c9ec6SMichael Chan return -EINVAL; 909068c9ec6SMichael Chan 910068c9ec6SMichael Chan if (channel->combined_count && 911068c9ec6SMichael Chan (channel->rx_count || channel->tx_count)) 912068c9ec6SMichael Chan return -EINVAL; 913068c9ec6SMichael Chan 91476595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || 91576595193SPrashant Sreedharan channel->tx_count)) 91676595193SPrashant Sreedharan return -EINVAL; 91776595193SPrashant Sreedharan 918068c9ec6SMichael Chan if (channel->combined_count) 919068c9ec6SMichael Chan sh = true; 920068c9ec6SMichael Chan 921c0c050c5SMichael Chan tcs = netdev_get_num_tc(dev); 922c0c050c5SMichael Chan 923391be5c2SMichael Chan req_tx_rings = sh ? channel->combined_count : channel->tx_count; 924d1e7925eSMichael Chan req_rx_rings = sh ? channel->combined_count : channel->rx_count; 9255f449249SMichael Chan if (bp->tx_nr_rings_xdp) { 9265f449249SMichael Chan if (!sh) { 9275f449249SMichael Chan netdev_err(dev, "Only combined mode supported when XDP is enabled.\n"); 9285f449249SMichael Chan return -EINVAL; 9295f449249SMichael Chan } 9305f449249SMichael Chan tx_xdp = req_rx_rings; 9315f449249SMichael Chan } 93298fdbe73SMichael Chan rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); 933d1e7925eSMichael Chan if (rc) { 934d1e7925eSMichael Chan netdev_warn(dev, "Unable to allocate the requested rings\n"); 935d1e7925eSMichael Chan return rc; 936391be5c2SMichael Chan } 937391be5c2SMichael Chan 938bd3191b5SMichael Chan if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != 939bd3191b5SMichael Chan bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && 9404b70dce2SJuhee Kang netif_is_rxfh_configured(dev)) { 941bd3191b5SMichael Chan netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n"); 942bd3191b5SMichael Chan return -EINVAL; 943bd3191b5SMichael Chan } 944bd3191b5SMichael Chan 945c0c050c5SMichael Chan if (netif_running(dev)) { 946c0c050c5SMichael Chan if (BNXT_PF(bp)) { 947c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 948c0c050c5SMichael Chan * before PF unload 949c0c050c5SMichael Chan */ 950c0c050c5SMichael Chan } 951c0c050c5SMichael Chan rc = bnxt_close_nic(bp, true, false); 952c0c050c5SMichael Chan if (rc) { 953c0c050c5SMichael Chan netdev_err(bp->dev, "Set channel failure rc :%x\n", 954c0c050c5SMichael Chan rc); 955c0c050c5SMichael Chan return rc; 956c0c050c5SMichael Chan } 957c0c050c5SMichael Chan } 958c0c050c5SMichael Chan 959068c9ec6SMichael Chan if (sh) { 960068c9ec6SMichael Chan bp->flags |= BNXT_FLAG_SHARED_RINGS; 961d1e7925eSMichael Chan bp->rx_nr_rings = channel->combined_count; 962d1e7925eSMichael Chan bp->tx_nr_rings_per_tc = channel->combined_count; 963068c9ec6SMichael Chan } else { 964068c9ec6SMichael Chan bp->flags &= ~BNXT_FLAG_SHARED_RINGS; 965c0c050c5SMichael Chan bp->rx_nr_rings = channel->rx_count; 966c0c050c5SMichael Chan bp->tx_nr_rings_per_tc = channel->tx_count; 967068c9ec6SMichael Chan } 9685f449249SMichael Chan bp->tx_nr_rings_xdp = tx_xdp; 9695f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; 970c0c050c5SMichael Chan if (tcs > 1) 9715f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; 972068c9ec6SMichael Chan 973068c9ec6SMichael Chan bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : 974068c9ec6SMichael Chan bp->tx_nr_rings + bp->rx_nr_rings; 975068c9ec6SMichael Chan 9762bcfa6f6SMichael Chan /* After changing number of rx channels, update NTUPLE feature. */ 9772bcfa6f6SMichael Chan netdev_update_features(dev); 978c0c050c5SMichael Chan if (netif_running(dev)) { 979c0c050c5SMichael Chan rc = bnxt_open_nic(bp, true, false); 980c0c050c5SMichael Chan if ((!rc) && BNXT_PF(bp)) { 981c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 982c0c050c5SMichael Chan * to renable 983c0c050c5SMichael Chan */ 984c0c050c5SMichael Chan } 985d8c09f19SMichael Chan } else { 9861b3f0b75SMichael Chan rc = bnxt_reserve_rings(bp, true); 987c0c050c5SMichael Chan } 988c0c050c5SMichael Chan 989c0c050c5SMichael Chan return rc; 990c0c050c5SMichael Chan } 991c0c050c5SMichael Chan 992c0c050c5SMichael Chan #ifdef CONFIG_RFS_ACCEL 993c0c050c5SMichael Chan static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, 994c0c050c5SMichael Chan u32 *rule_locs) 995c0c050c5SMichael Chan { 996c0c050c5SMichael Chan int i, j = 0; 997c0c050c5SMichael Chan 998c0c050c5SMichael Chan cmd->data = bp->ntp_fltr_count; 999c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 1000c0c050c5SMichael Chan struct hlist_head *head; 1001c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 1002c0c050c5SMichael Chan 1003c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1004c0c050c5SMichael Chan rcu_read_lock(); 1005c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1006c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1007c0c050c5SMichael Chan break; 1008c0c050c5SMichael Chan rule_locs[j++] = fltr->sw_id; 1009c0c050c5SMichael Chan } 1010c0c050c5SMichael Chan rcu_read_unlock(); 1011c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1012c0c050c5SMichael Chan break; 1013c0c050c5SMichael Chan } 1014c0c050c5SMichael Chan cmd->rule_cnt = j; 1015c0c050c5SMichael Chan return 0; 1016c0c050c5SMichael Chan } 1017c0c050c5SMichael Chan 1018c0c050c5SMichael Chan static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1019c0c050c5SMichael Chan { 1020c0c050c5SMichael Chan struct ethtool_rx_flow_spec *fs = 1021c0c050c5SMichael Chan (struct ethtool_rx_flow_spec *)&cmd->fs; 1022c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 1023c0c050c5SMichael Chan struct flow_keys *fkeys; 1024c0c050c5SMichael Chan int i, rc = -EINVAL; 1025c0c050c5SMichael Chan 1026b721cfafSstephen hemminger if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) 1027c0c050c5SMichael Chan return rc; 1028c0c050c5SMichael Chan 1029c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 1030c0c050c5SMichael Chan struct hlist_head *head; 1031c0c050c5SMichael Chan 1032c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1033c0c050c5SMichael Chan rcu_read_lock(); 1034c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1035c0c050c5SMichael Chan if (fltr->sw_id == fs->location) 1036c0c050c5SMichael Chan goto fltr_found; 1037c0c050c5SMichael Chan } 1038c0c050c5SMichael Chan rcu_read_unlock(); 1039c0c050c5SMichael Chan } 1040c0c050c5SMichael Chan return rc; 1041c0c050c5SMichael Chan 1042c0c050c5SMichael Chan fltr_found: 1043c0c050c5SMichael Chan fkeys = &fltr->fkeys; 1044dda0e746SMichael Chan if (fkeys->basic.n_proto == htons(ETH_P_IP)) { 1045c0c050c5SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1046c0c050c5SMichael Chan fs->flow_type = TCP_V4_FLOW; 1047c0c050c5SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1048c0c050c5SMichael Chan fs->flow_type = UDP_V4_FLOW; 1049c0c050c5SMichael Chan else 1050c0c050c5SMichael Chan goto fltr_err; 1051c0c050c5SMichael Chan 1052c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; 1053c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); 1054c0c050c5SMichael Chan 1055c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; 1056c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); 1057c0c050c5SMichael Chan 1058c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; 1059c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); 1060c0c050c5SMichael Chan 1061c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; 1062c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); 1063dda0e746SMichael Chan } else { 1064dda0e746SMichael Chan int i; 1065dda0e746SMichael Chan 1066dda0e746SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1067dda0e746SMichael Chan fs->flow_type = TCP_V6_FLOW; 1068dda0e746SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1069dda0e746SMichael Chan fs->flow_type = UDP_V6_FLOW; 1070dda0e746SMichael Chan else 1071dda0e746SMichael Chan goto fltr_err; 1072dda0e746SMichael Chan 1073dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = 1074dda0e746SMichael Chan fkeys->addrs.v6addrs.src; 1075dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = 1076dda0e746SMichael Chan fkeys->addrs.v6addrs.dst; 1077dda0e746SMichael Chan for (i = 0; i < 4; i++) { 1078dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); 1079dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); 1080dda0e746SMichael Chan } 1081dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; 1082dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); 1083dda0e746SMichael Chan 1084dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; 1085dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); 1086dda0e746SMichael Chan } 1087c0c050c5SMichael Chan 1088c0c050c5SMichael Chan fs->ring_cookie = fltr->rxq; 1089c0c050c5SMichael Chan rc = 0; 1090c0c050c5SMichael Chan 1091c0c050c5SMichael Chan fltr_err: 1092c0c050c5SMichael Chan rcu_read_unlock(); 1093c0c050c5SMichael Chan 1094c0c050c5SMichael Chan return rc; 1095c0c050c5SMichael Chan } 1096a011952aSMichael Chan #endif 1097a011952aSMichael Chan 1098a011952aSMichael Chan static u64 get_ethtool_ipv4_rss(struct bnxt *bp) 1099a011952aSMichael Chan { 1100a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) 1101a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1102a011952aSMichael Chan return 0; 1103a011952aSMichael Chan } 1104a011952aSMichael Chan 1105a011952aSMichael Chan static u64 get_ethtool_ipv6_rss(struct bnxt *bp) 1106a011952aSMichael Chan { 1107a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) 1108a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1109a011952aSMichael Chan return 0; 1110a011952aSMichael Chan } 1111a011952aSMichael Chan 1112a011952aSMichael Chan static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1113a011952aSMichael Chan { 1114a011952aSMichael Chan cmd->data = 0; 1115a011952aSMichael Chan switch (cmd->flow_type) { 1116a011952aSMichael Chan case TCP_V4_FLOW: 1117a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) 1118a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1119a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1120a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1121a011952aSMichael Chan break; 1122a011952aSMichael Chan case UDP_V4_FLOW: 1123a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) 1124a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1125a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1126df561f66SGustavo A. R. Silva fallthrough; 1127a011952aSMichael Chan case SCTP_V4_FLOW: 1128a011952aSMichael Chan case AH_ESP_V4_FLOW: 1129a011952aSMichael Chan case AH_V4_FLOW: 1130a011952aSMichael Chan case ESP_V4_FLOW: 1131a011952aSMichael Chan case IPV4_FLOW: 1132a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1133a011952aSMichael Chan break; 1134a011952aSMichael Chan 1135a011952aSMichael Chan case TCP_V6_FLOW: 1136a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) 1137a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1138a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1139a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1140a011952aSMichael Chan break; 1141a011952aSMichael Chan case UDP_V6_FLOW: 1142a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) 1143a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1144a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1145df561f66SGustavo A. R. Silva fallthrough; 1146a011952aSMichael Chan case SCTP_V6_FLOW: 1147a011952aSMichael Chan case AH_ESP_V6_FLOW: 1148a011952aSMichael Chan case AH_V6_FLOW: 1149a011952aSMichael Chan case ESP_V6_FLOW: 1150a011952aSMichael Chan case IPV6_FLOW: 1151a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1152a011952aSMichael Chan break; 1153a011952aSMichael Chan } 1154a011952aSMichael Chan return 0; 1155a011952aSMichael Chan } 1156a011952aSMichael Chan 1157a011952aSMichael Chan #define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 1158a011952aSMichael Chan #define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) 1159a011952aSMichael Chan 1160a011952aSMichael Chan static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1161a011952aSMichael Chan { 1162a011952aSMichael Chan u32 rss_hash_cfg = bp->rss_hash_cfg; 1163a011952aSMichael Chan int tuple, rc = 0; 1164a011952aSMichael Chan 1165a011952aSMichael Chan if (cmd->data == RXH_4TUPLE) 1166a011952aSMichael Chan tuple = 4; 1167a011952aSMichael Chan else if (cmd->data == RXH_2TUPLE) 1168a011952aSMichael Chan tuple = 2; 1169a011952aSMichael Chan else if (!cmd->data) 1170a011952aSMichael Chan tuple = 0; 1171a011952aSMichael Chan else 1172a011952aSMichael Chan return -EINVAL; 1173a011952aSMichael Chan 1174a011952aSMichael Chan if (cmd->flow_type == TCP_V4_FLOW) { 1175a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1176a011952aSMichael Chan if (tuple == 4) 1177a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1178a011952aSMichael Chan } else if (cmd->flow_type == UDP_V4_FLOW) { 1179a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1180a011952aSMichael Chan return -EINVAL; 1181a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1182a011952aSMichael Chan if (tuple == 4) 1183a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1184a011952aSMichael Chan } else if (cmd->flow_type == TCP_V6_FLOW) { 1185a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1186a011952aSMichael Chan if (tuple == 4) 1187a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1188a011952aSMichael Chan } else if (cmd->flow_type == UDP_V6_FLOW) { 1189a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1190a011952aSMichael Chan return -EINVAL; 1191a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1192a011952aSMichael Chan if (tuple == 4) 1193a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1194a011952aSMichael Chan } else if (tuple == 4) { 1195a011952aSMichael Chan return -EINVAL; 1196a011952aSMichael Chan } 1197a011952aSMichael Chan 1198a011952aSMichael Chan switch (cmd->flow_type) { 1199a011952aSMichael Chan case TCP_V4_FLOW: 1200a011952aSMichael Chan case UDP_V4_FLOW: 1201a011952aSMichael Chan case SCTP_V4_FLOW: 1202a011952aSMichael Chan case AH_ESP_V4_FLOW: 1203a011952aSMichael Chan case AH_V4_FLOW: 1204a011952aSMichael Chan case ESP_V4_FLOW: 1205a011952aSMichael Chan case IPV4_FLOW: 1206a011952aSMichael Chan if (tuple == 2) 1207a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1208a011952aSMichael Chan else if (!tuple) 1209a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1210a011952aSMichael Chan break; 1211a011952aSMichael Chan 1212a011952aSMichael Chan case TCP_V6_FLOW: 1213a011952aSMichael Chan case UDP_V6_FLOW: 1214a011952aSMichael Chan case SCTP_V6_FLOW: 1215a011952aSMichael Chan case AH_ESP_V6_FLOW: 1216a011952aSMichael Chan case AH_V6_FLOW: 1217a011952aSMichael Chan case ESP_V6_FLOW: 1218a011952aSMichael Chan case IPV6_FLOW: 1219a011952aSMichael Chan if (tuple == 2) 1220a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1221a011952aSMichael Chan else if (!tuple) 1222a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1223a011952aSMichael Chan break; 1224a011952aSMichael Chan } 1225a011952aSMichael Chan 1226a011952aSMichael Chan if (bp->rss_hash_cfg == rss_hash_cfg) 1227a011952aSMichael Chan return 0; 1228a011952aSMichael Chan 1229a011952aSMichael Chan bp->rss_hash_cfg = rss_hash_cfg; 1230a011952aSMichael Chan if (netif_running(bp->dev)) { 1231a011952aSMichael Chan bnxt_close_nic(bp, false, false); 1232a011952aSMichael Chan rc = bnxt_open_nic(bp, false, false); 1233a011952aSMichael Chan } 1234a011952aSMichael Chan return rc; 1235a011952aSMichael Chan } 1236c0c050c5SMichael Chan 1237c0c050c5SMichael Chan static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 1238c0c050c5SMichael Chan u32 *rule_locs) 1239c0c050c5SMichael Chan { 1240c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1241c0c050c5SMichael Chan int rc = 0; 1242c0c050c5SMichael Chan 1243c0c050c5SMichael Chan switch (cmd->cmd) { 1244a011952aSMichael Chan #ifdef CONFIG_RFS_ACCEL 1245c0c050c5SMichael Chan case ETHTOOL_GRXRINGS: 1246c0c050c5SMichael Chan cmd->data = bp->rx_nr_rings; 1247c0c050c5SMichael Chan break; 1248c0c050c5SMichael Chan 1249c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLCNT: 1250c0c050c5SMichael Chan cmd->rule_cnt = bp->ntp_fltr_count; 1251c0c050c5SMichael Chan cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 1252c0c050c5SMichael Chan break; 1253c0c050c5SMichael Chan 1254c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLALL: 1255c0c050c5SMichael Chan rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 1256c0c050c5SMichael Chan break; 1257c0c050c5SMichael Chan 1258c0c050c5SMichael Chan case ETHTOOL_GRXCLSRULE: 1259c0c050c5SMichael Chan rc = bnxt_grxclsrule(bp, cmd); 1260c0c050c5SMichael Chan break; 1261a011952aSMichael Chan #endif 1262a011952aSMichael Chan 1263a011952aSMichael Chan case ETHTOOL_GRXFH: 1264a011952aSMichael Chan rc = bnxt_grxfh(bp, cmd); 1265a011952aSMichael Chan break; 1266c0c050c5SMichael Chan 1267c0c050c5SMichael Chan default: 1268c0c050c5SMichael Chan rc = -EOPNOTSUPP; 1269c0c050c5SMichael Chan break; 1270c0c050c5SMichael Chan } 1271c0c050c5SMichael Chan 1272c0c050c5SMichael Chan return rc; 1273c0c050c5SMichael Chan } 1274a011952aSMichael Chan 1275a011952aSMichael Chan static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 1276a011952aSMichael Chan { 1277a011952aSMichael Chan struct bnxt *bp = netdev_priv(dev); 1278a011952aSMichael Chan int rc; 1279a011952aSMichael Chan 1280a011952aSMichael Chan switch (cmd->cmd) { 1281a011952aSMichael Chan case ETHTOOL_SRXFH: 1282a011952aSMichael Chan rc = bnxt_srxfh(bp, cmd); 1283a011952aSMichael Chan break; 1284a011952aSMichael Chan 1285a011952aSMichael Chan default: 1286a011952aSMichael Chan rc = -EOPNOTSUPP; 1287a011952aSMichael Chan break; 1288a011952aSMichael Chan } 1289a011952aSMichael Chan return rc; 1290a011952aSMichael Chan } 1291c0c050c5SMichael Chan 1292b73c1d08SMichael Chan u32 bnxt_get_rxfh_indir_size(struct net_device *dev) 1293c0c050c5SMichael Chan { 1294b73c1d08SMichael Chan struct bnxt *bp = netdev_priv(dev); 1295b73c1d08SMichael Chan 1296b73c1d08SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 1297b73c1d08SMichael Chan return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 1298c0c050c5SMichael Chan return HW_HASH_INDEX_SIZE; 1299c0c050c5SMichael Chan } 1300c0c050c5SMichael Chan 1301c0c050c5SMichael Chan static u32 bnxt_get_rxfh_key_size(struct net_device *dev) 1302c0c050c5SMichael Chan { 1303c0c050c5SMichael Chan return HW_HASH_KEY_SIZE; 1304c0c050c5SMichael Chan } 1305c0c050c5SMichael Chan 1306c0c050c5SMichael Chan static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 1307c0c050c5SMichael Chan u8 *hfunc) 1308c0c050c5SMichael Chan { 1309c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 13107991cb9cSMichael Chan struct bnxt_vnic_info *vnic; 1311adc38ac6SMichael Chan u32 i, tbl_size; 1312c0c050c5SMichael Chan 1313c0c050c5SMichael Chan if (hfunc) 1314c0c050c5SMichael Chan *hfunc = ETH_RSS_HASH_TOP; 1315c0c050c5SMichael Chan 13167991cb9cSMichael Chan if (!bp->vnic_info) 13177991cb9cSMichael Chan return 0; 13187991cb9cSMichael Chan 13197991cb9cSMichael Chan vnic = &bp->vnic_info[0]; 1320adc38ac6SMichael Chan if (indir && bp->rss_indir_tbl) { 1321adc38ac6SMichael Chan tbl_size = bnxt_get_rxfh_indir_size(dev); 1322adc38ac6SMichael Chan for (i = 0; i < tbl_size; i++) 1323adc38ac6SMichael Chan indir[i] = bp->rss_indir_tbl[i]; 13247991cb9cSMichael Chan } 1325c0c050c5SMichael Chan 13267991cb9cSMichael Chan if (key && vnic->rss_hash_key) 1327c0c050c5SMichael Chan memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 1328c0c050c5SMichael Chan 1329c0c050c5SMichael Chan return 0; 1330c0c050c5SMichael Chan } 1331c0c050c5SMichael Chan 1332bd3191b5SMichael Chan static int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 1333bd3191b5SMichael Chan const u8 *key, const u8 hfunc) 1334bd3191b5SMichael Chan { 1335bd3191b5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1336bd3191b5SMichael Chan int rc = 0; 1337bd3191b5SMichael Chan 1338bd3191b5SMichael Chan if (hfunc && hfunc != ETH_RSS_HASH_TOP) 1339bd3191b5SMichael Chan return -EOPNOTSUPP; 1340bd3191b5SMichael Chan 1341bd3191b5SMichael Chan if (key) 1342bd3191b5SMichael Chan return -EOPNOTSUPP; 1343bd3191b5SMichael Chan 1344bd3191b5SMichael Chan if (indir) { 1345bd3191b5SMichael Chan u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 1346bd3191b5SMichael Chan 1347bd3191b5SMichael Chan for (i = 0; i < tbl_size; i++) 1348bd3191b5SMichael Chan bp->rss_indir_tbl[i] = indir[i]; 1349bd3191b5SMichael Chan pad = bp->rss_indir_tbl_entries - tbl_size; 1350bd3191b5SMichael Chan if (pad) 1351bd3191b5SMichael Chan memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 1352bd3191b5SMichael Chan } 1353bd3191b5SMichael Chan 1354bd3191b5SMichael Chan if (netif_running(bp->dev)) { 1355bd3191b5SMichael Chan bnxt_close_nic(bp, false, false); 1356bd3191b5SMichael Chan rc = bnxt_open_nic(bp, false, false); 1357bd3191b5SMichael Chan } 1358bd3191b5SMichael Chan return rc; 1359bd3191b5SMichael Chan } 1360bd3191b5SMichael Chan 1361c0c050c5SMichael Chan static void bnxt_get_drvinfo(struct net_device *dev, 1362c0c050c5SMichael Chan struct ethtool_drvinfo *info) 1363c0c050c5SMichael Chan { 1364c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1365c0c050c5SMichael Chan 1366c0c050c5SMichael Chan strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 1367431aa1ebSMichael Chan strlcpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 1368c0c050c5SMichael Chan strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 13695c8227d0SMichael Chan info->n_stats = bnxt_get_num_stats(bp); 1370eb513658SMichael Chan info->testinfo_len = bp->num_tests; 1371c0c050c5SMichael Chan /* TODO CHIMP_FW: eeprom dump details */ 1372c0c050c5SMichael Chan info->eedump_len = 0; 1373c0c050c5SMichael Chan /* TODO CHIMP FW: reg dump details */ 1374c0c050c5SMichael Chan info->regdump_len = 0; 1375c0c050c5SMichael Chan } 1376c0c050c5SMichael Chan 1377b5d600b0SVasundhara Volam static int bnxt_get_regs_len(struct net_device *dev) 1378b5d600b0SVasundhara Volam { 1379b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1380b5d600b0SVasundhara Volam int reg_len; 1381b5d600b0SVasundhara Volam 1382f0f47b2fSVasundhara Volam if (!BNXT_PF(bp)) 1383f0f47b2fSVasundhara Volam return -EOPNOTSUPP; 1384f0f47b2fSVasundhara Volam 1385b5d600b0SVasundhara Volam reg_len = BNXT_PXP_REG_LEN; 1386b5d600b0SVasundhara Volam 1387b5d600b0SVasundhara Volam if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 1388b5d600b0SVasundhara Volam reg_len += sizeof(struct pcie_ctx_hw_stats); 1389b5d600b0SVasundhara Volam 1390b5d600b0SVasundhara Volam return reg_len; 1391b5d600b0SVasundhara Volam } 1392b5d600b0SVasundhara Volam 1393b5d600b0SVasundhara Volam static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 1394b5d600b0SVasundhara Volam void *_p) 1395b5d600b0SVasundhara Volam { 1396b5d600b0SVasundhara Volam struct pcie_ctx_hw_stats *hw_pcie_stats; 1397bbf33d1dSEdwin Peer struct hwrm_pcie_qstats_input *req; 1398b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1399b5d600b0SVasundhara Volam dma_addr_t hw_pcie_stats_addr; 1400b5d600b0SVasundhara Volam int rc; 1401b5d600b0SVasundhara Volam 1402b5d600b0SVasundhara Volam regs->version = 0; 1403b5d600b0SVasundhara Volam bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 1404b5d600b0SVasundhara Volam 1405b5d600b0SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 1406b5d600b0SVasundhara Volam return; 1407b5d600b0SVasundhara Volam 1408bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) 1409b5d600b0SVasundhara Volam return; 1410b5d600b0SVasundhara Volam 1411bbf33d1dSEdwin Peer hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), 1412bbf33d1dSEdwin Peer &hw_pcie_stats_addr); 1413bbf33d1dSEdwin Peer if (!hw_pcie_stats) { 1414bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1415bbf33d1dSEdwin Peer return; 1416bbf33d1dSEdwin Peer } 1417bbf33d1dSEdwin Peer 1418b5d600b0SVasundhara Volam regs->version = 1; 1419bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold on to slice */ 1420bbf33d1dSEdwin Peer req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 1421bbf33d1dSEdwin Peer req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 1422bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 1423b5d600b0SVasundhara Volam if (!rc) { 1424b5d600b0SVasundhara Volam __le64 *src = (__le64 *)hw_pcie_stats; 1425b5d600b0SVasundhara Volam u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 1426b5d600b0SVasundhara Volam int i; 1427b5d600b0SVasundhara Volam 1428b5d600b0SVasundhara Volam for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 1429b5d600b0SVasundhara Volam dst[i] = le64_to_cpu(src[i]); 1430b5d600b0SVasundhara Volam } 1431bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1432b5d600b0SVasundhara Volam } 1433b5d600b0SVasundhara Volam 14348e202366SMichael Chan static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14358e202366SMichael Chan { 14368e202366SMichael Chan struct bnxt *bp = netdev_priv(dev); 14378e202366SMichael Chan 14388e202366SMichael Chan wol->supported = 0; 14398e202366SMichael Chan wol->wolopts = 0; 14408e202366SMichael Chan memset(&wol->sopass, 0, sizeof(wol->sopass)); 14418e202366SMichael Chan if (bp->flags & BNXT_FLAG_WOL_CAP) { 14428e202366SMichael Chan wol->supported = WAKE_MAGIC; 14438e202366SMichael Chan if (bp->wol) 14448e202366SMichael Chan wol->wolopts = WAKE_MAGIC; 14458e202366SMichael Chan } 14468e202366SMichael Chan } 14478e202366SMichael Chan 14485282db6cSMichael Chan static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14495282db6cSMichael Chan { 14505282db6cSMichael Chan struct bnxt *bp = netdev_priv(dev); 14515282db6cSMichael Chan 14525282db6cSMichael Chan if (wol->wolopts & ~WAKE_MAGIC) 14535282db6cSMichael Chan return -EINVAL; 14545282db6cSMichael Chan 14555282db6cSMichael Chan if (wol->wolopts & WAKE_MAGIC) { 14565282db6cSMichael Chan if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 14575282db6cSMichael Chan return -EINVAL; 14585282db6cSMichael Chan if (!bp->wol) { 14595282db6cSMichael Chan if (bnxt_hwrm_alloc_wol_fltr(bp)) 14605282db6cSMichael Chan return -EBUSY; 14615282db6cSMichael Chan bp->wol = 1; 14625282db6cSMichael Chan } 14635282db6cSMichael Chan } else { 14645282db6cSMichael Chan if (bp->wol) { 14655282db6cSMichael Chan if (bnxt_hwrm_free_wol_fltr(bp)) 14665282db6cSMichael Chan return -EBUSY; 14675282db6cSMichael Chan bp->wol = 0; 14685282db6cSMichael Chan } 14695282db6cSMichael Chan } 14705282db6cSMichael Chan return 0; 14715282db6cSMichael Chan } 14725282db6cSMichael Chan 1473170ce013SMichael Chan u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 1474c0c050c5SMichael Chan { 1475c0c050c5SMichael Chan u32 speed_mask = 0; 1476c0c050c5SMichael Chan 1477c0c050c5SMichael Chan /* TODO: support 25GB, 40GB, 50GB with different cable type */ 1478c0c050c5SMichael Chan /* set the advertised speeds */ 1479c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 1480c0c050c5SMichael Chan speed_mask |= ADVERTISED_100baseT_Full; 1481c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 1482c0c050c5SMichael Chan speed_mask |= ADVERTISED_1000baseT_Full; 1483c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 1484c0c050c5SMichael Chan speed_mask |= ADVERTISED_2500baseX_Full; 1485c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 1486c0c050c5SMichael Chan speed_mask |= ADVERTISED_10000baseT_Full; 1487c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 14881c49c421SMichael Chan speed_mask |= ADVERTISED_40000baseCR4_Full; 148927c4d578SMichael Chan 149027c4d578SMichael Chan if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 149127c4d578SMichael Chan speed_mask |= ADVERTISED_Pause; 149227c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_TX) 149327c4d578SMichael Chan speed_mask |= ADVERTISED_Asym_Pause; 149427c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_RX) 149527c4d578SMichael Chan speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 149627c4d578SMichael Chan 1497c0c050c5SMichael Chan return speed_mask; 1498c0c050c5SMichael Chan } 1499c0c050c5SMichael Chan 150000c04a92SMichael Chan #define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 150100c04a92SMichael Chan { \ 150200c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 150300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150400c04a92SMichael Chan 100baseT_Full); \ 150500c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 150600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150700c04a92SMichael Chan 1000baseT_Full); \ 150800c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 150900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151000c04a92SMichael Chan 10000baseT_Full); \ 151100c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 151200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151300c04a92SMichael Chan 25000baseCR_Full); \ 151400c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 151500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151600c04a92SMichael Chan 40000baseCR4_Full);\ 151700c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 151800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151900c04a92SMichael Chan 50000baseCR2_Full);\ 152038a21b34SDeepak Khungar if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 152138a21b34SDeepak Khungar ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152238a21b34SDeepak Khungar 100000baseCR4_Full);\ 152300c04a92SMichael Chan if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 152400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152500c04a92SMichael Chan Pause); \ 152600c04a92SMichael Chan if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 152700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode( \ 152800c04a92SMichael Chan lk_ksettings, name, Asym_Pause);\ 152900c04a92SMichael Chan } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 153000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153100c04a92SMichael Chan Asym_Pause); \ 153200c04a92SMichael Chan } \ 153300c04a92SMichael Chan } 153400c04a92SMichael Chan 153500c04a92SMichael Chan #define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 153600c04a92SMichael Chan { \ 153700c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 153800c04a92SMichael Chan 100baseT_Full) || \ 153900c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154000c04a92SMichael Chan 100baseT_Half)) \ 154100c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 154200c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154300c04a92SMichael Chan 1000baseT_Full) || \ 154400c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154500c04a92SMichael Chan 1000baseT_Half)) \ 154600c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 154700c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154800c04a92SMichael Chan 10000baseT_Full)) \ 154900c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 155000c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155100c04a92SMichael Chan 25000baseCR_Full)) \ 155200c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 155300c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155400c04a92SMichael Chan 40000baseCR4_Full)) \ 155500c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 155600c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155700c04a92SMichael Chan 50000baseCR2_Full)) \ 155800c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 155938a21b34SDeepak Khungar if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156038a21b34SDeepak Khungar 100000baseCR4_Full)) \ 156138a21b34SDeepak Khungar (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 156200c04a92SMichael Chan } 156300c04a92SMichael Chan 1564532262baSEdwin Peer #define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1565532262baSEdwin Peer { \ 1566532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 1567532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1568532262baSEdwin Peer 50000baseCR_Full); \ 1569532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 1570532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1571532262baSEdwin Peer 100000baseCR2_Full);\ 1572532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 1573532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1574532262baSEdwin Peer 200000baseCR4_Full);\ 1575532262baSEdwin Peer } 1576532262baSEdwin Peer 1577532262baSEdwin Peer #define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1578532262baSEdwin Peer { \ 1579532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1580532262baSEdwin Peer 50000baseCR_Full)) \ 1581532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 1582532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1583532262baSEdwin Peer 100000baseCR2_Full)) \ 1584532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 1585532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1586532262baSEdwin Peer 200000baseCR4_Full)) \ 1587532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 1588532262baSEdwin Peer } 1589532262baSEdwin Peer 15908b277589SMichael Chan static void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 15918b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 15928b277589SMichael Chan { 15938b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 15948b277589SMichael Chan 15958b277589SMichael Chan if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 15968b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 15978b277589SMichael Chan lk_ksettings->link_modes.advertising); 15988b277589SMichael Chan return; 15998b277589SMichael Chan } 16008b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 16018b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16028b277589SMichael Chan lk_ksettings->link_modes.advertising); 16038b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 16048b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16058b277589SMichael Chan lk_ksettings->link_modes.advertising); 16068b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 16078b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16088b277589SMichael Chan lk_ksettings->link_modes.advertising); 16098b277589SMichael Chan } 16108b277589SMichael Chan 161100c04a92SMichael Chan static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 161200c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 161327c4d578SMichael Chan { 161468515a18SMichael Chan u16 fw_speeds = link_info->advertising; 161527c4d578SMichael Chan u8 fw_pause = 0; 161627c4d578SMichael Chan 161727c4d578SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 161827c4d578SMichael Chan fw_pause = link_info->auto_pause_setting; 161927c4d578SMichael Chan 162000c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 1621532262baSEdwin Peer fw_speeds = link_info->advertising_pam4; 1622532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 16238b277589SMichael Chan bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 162427c4d578SMichael Chan } 162527c4d578SMichael Chan 162600c04a92SMichael Chan static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 162700c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16283277360eSMichael Chan { 16293277360eSMichael Chan u16 fw_speeds = link_info->lp_auto_link_speeds; 16303277360eSMichael Chan u8 fw_pause = 0; 16313277360eSMichael Chan 16323277360eSMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 16333277360eSMichael Chan fw_pause = link_info->lp_pause; 16343277360eSMichael Chan 163500c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 163600c04a92SMichael Chan lp_advertising); 1637532262baSEdwin Peer fw_speeds = link_info->lp_auto_pam4_link_speeds; 1638532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 16393277360eSMichael Chan } 16403277360eSMichael Chan 16418b277589SMichael Chan static void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 16428b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16438b277589SMichael Chan { 16448b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16458b277589SMichael Chan 16468b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 16478b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16488b277589SMichael Chan lk_ksettings->link_modes.supported); 16498b277589SMichael Chan return; 16508b277589SMichael Chan } 16518b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 16528b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16538b277589SMichael Chan lk_ksettings->link_modes.supported); 16548b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 16558b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16568b277589SMichael Chan lk_ksettings->link_modes.supported); 16578b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 16588b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16598b277589SMichael Chan lk_ksettings->link_modes.supported); 16608b277589SMichael Chan } 16618b277589SMichael Chan 166200c04a92SMichael Chan static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 166300c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16644b32caccSMichael Chan { 16654b32caccSMichael Chan u16 fw_speeds = link_info->support_speeds; 16664b32caccSMichael Chan 166700c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 1668532262baSEdwin Peer fw_speeds = link_info->support_pam4_speeds; 1669532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16704b32caccSMichael Chan 167100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause); 167200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167300c04a92SMichael Chan Asym_Pause); 167493ed8117SMichael Chan 1675532262baSEdwin Peer if (link_info->support_auto_speeds || 1676532262baSEdwin Peer link_info->support_pam4_auto_speeds) 167700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167800c04a92SMichael Chan Autoneg); 16798b277589SMichael Chan bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 168093ed8117SMichael Chan } 168193ed8117SMichael Chan 1682c0c050c5SMichael Chan u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 1683c0c050c5SMichael Chan { 1684c0c050c5SMichael Chan switch (fw_link_speed) { 1685c0c050c5SMichael Chan case BNXT_LINK_SPEED_100MB: 1686c0c050c5SMichael Chan return SPEED_100; 1687c0c050c5SMichael Chan case BNXT_LINK_SPEED_1GB: 1688c0c050c5SMichael Chan return SPEED_1000; 1689c0c050c5SMichael Chan case BNXT_LINK_SPEED_2_5GB: 1690c0c050c5SMichael Chan return SPEED_2500; 1691c0c050c5SMichael Chan case BNXT_LINK_SPEED_10GB: 1692c0c050c5SMichael Chan return SPEED_10000; 1693c0c050c5SMichael Chan case BNXT_LINK_SPEED_20GB: 1694c0c050c5SMichael Chan return SPEED_20000; 1695c0c050c5SMichael Chan case BNXT_LINK_SPEED_25GB: 1696c0c050c5SMichael Chan return SPEED_25000; 1697c0c050c5SMichael Chan case BNXT_LINK_SPEED_40GB: 1698c0c050c5SMichael Chan return SPEED_40000; 1699c0c050c5SMichael Chan case BNXT_LINK_SPEED_50GB: 1700c0c050c5SMichael Chan return SPEED_50000; 170138a21b34SDeepak Khungar case BNXT_LINK_SPEED_100GB: 170238a21b34SDeepak Khungar return SPEED_100000; 1703c0c050c5SMichael Chan default: 1704c0c050c5SMichael Chan return SPEED_UNKNOWN; 1705c0c050c5SMichael Chan } 1706c0c050c5SMichael Chan } 1707c0c050c5SMichael Chan 170800c04a92SMichael Chan static int bnxt_get_link_ksettings(struct net_device *dev, 170900c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 1710c0c050c5SMichael Chan { 1711c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1712c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 171300c04a92SMichael Chan struct ethtool_link_settings *base = &lk_ksettings->base; 171400c04a92SMichael Chan u32 ethtool_speed; 1715c0c050c5SMichael Chan 171600c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 1717e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 171800c04a92SMichael Chan bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 1719c0c050c5SMichael Chan 172000c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 1721b763499eSMichael Chan if (link_info->autoneg) { 172200c04a92SMichael Chan bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 172300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, 172400c04a92SMichael Chan advertising, Autoneg); 172500c04a92SMichael Chan base->autoneg = AUTONEG_ENABLE; 172600c04a92SMichael Chan base->duplex = DUPLEX_UNKNOWN; 172783d8f5e9SMichael Chan if (link_info->phy_link_status == BNXT_LINK_LINK) { 172883d8f5e9SMichael Chan bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 172983d8f5e9SMichael Chan if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 173000c04a92SMichael Chan base->duplex = DUPLEX_FULL; 173129c262feSMichael Chan else 173200c04a92SMichael Chan base->duplex = DUPLEX_HALF; 173383d8f5e9SMichael Chan } 173483d8f5e9SMichael Chan ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 1735c0c050c5SMichael Chan } else { 173600c04a92SMichael Chan base->autoneg = AUTONEG_DISABLE; 173729c262feSMichael Chan ethtool_speed = 173829c262feSMichael Chan bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 173900c04a92SMichael Chan base->duplex = DUPLEX_HALF; 174029c262feSMichael Chan if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 174100c04a92SMichael Chan base->duplex = DUPLEX_FULL; 1742c0c050c5SMichael Chan } 174300c04a92SMichael Chan base->speed = ethtool_speed; 1744c0c050c5SMichael Chan 174500c04a92SMichael Chan base->port = PORT_NONE; 1746c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 174700c04a92SMichael Chan base->port = PORT_TP; 174800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 174900c04a92SMichael Chan TP); 175000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 175100c04a92SMichael Chan TP); 1752c0c050c5SMichael Chan } else { 175300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 175400c04a92SMichael Chan FIBRE); 175500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 175600c04a92SMichael Chan FIBRE); 1757c0c050c5SMichael Chan 1758c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 175900c04a92SMichael Chan base->port = PORT_DA; 1760c0c050c5SMichael Chan else if (link_info->media_type == 1761c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 176200c04a92SMichael Chan base->port = PORT_FIBRE; 1763c0c050c5SMichael Chan } 176400c04a92SMichael Chan base->phy_address = link_info->phy_addr; 1765e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1766c0c050c5SMichael Chan 1767c0c050c5SMichael Chan return 0; 1768c0c050c5SMichael Chan } 1769c0c050c5SMichael Chan 1770f00530bfSEdwin Peer static int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 1771c0c050c5SMichael Chan { 17729d9cee08SMichael Chan struct bnxt *bp = netdev_priv(dev); 17739d9cee08SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 1774532262baSEdwin Peer u16 support_pam4_spds = link_info->support_pam4_speeds; 17759d9cee08SMichael Chan u16 support_spds = link_info->support_speeds; 1776532262baSEdwin Peer u8 sig_mode = BNXT_SIG_MODE_NRZ; 1777f00530bfSEdwin Peer u16 fw_speed = 0; 17789d9cee08SMichael Chan 1779c0c050c5SMichael Chan switch (ethtool_speed) { 1780c0c050c5SMichael Chan case SPEED_100: 17819d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 1782f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17839d9cee08SMichael Chan break; 1784c0c050c5SMichael Chan case SPEED_1000: 17859d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 1786f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 17879d9cee08SMichael Chan break; 1788c0c050c5SMichael Chan case SPEED_2500: 17899d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 1790f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 17919d9cee08SMichael Chan break; 1792c0c050c5SMichael Chan case SPEED_10000: 17939d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 1794f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 17959d9cee08SMichael Chan break; 1796c0c050c5SMichael Chan case SPEED_20000: 17979d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 1798f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 17999d9cee08SMichael Chan break; 1800c0c050c5SMichael Chan case SPEED_25000: 18019d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 1802f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 18039d9cee08SMichael Chan break; 1804c0c050c5SMichael Chan case SPEED_40000: 18059d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 1806f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 18079d9cee08SMichael Chan break; 1808c0c050c5SMichael Chan case SPEED_50000: 1809532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 1810f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 1811532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 1812532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 1813532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1814532262baSEdwin Peer } 18159d9cee08SMichael Chan break; 181638a21b34SDeepak Khungar case SPEED_100000: 1817532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 1818f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 1819532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 1820532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 1821532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1822532262baSEdwin Peer } 1823532262baSEdwin Peer break; 1824532262baSEdwin Peer case SPEED_200000: 1825532262baSEdwin Peer if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 1826532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 1827532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1828532262baSEdwin Peer } 1829c0c050c5SMichael Chan break; 1830c0c050c5SMichael Chan } 1831f00530bfSEdwin Peer 1832f00530bfSEdwin Peer if (!fw_speed) { 1833f00530bfSEdwin Peer netdev_err(dev, "unsupported speed!\n"); 1834f00530bfSEdwin Peer return -EINVAL; 1835f00530bfSEdwin Peer } 1836f00530bfSEdwin Peer 1837745b5c65SEdwin Peer if (link_info->req_link_speed == fw_speed && 1838745b5c65SEdwin Peer link_info->req_signal_mode == sig_mode && 1839745b5c65SEdwin Peer link_info->autoneg == 0) 1840745b5c65SEdwin Peer return -EALREADY; 1841745b5c65SEdwin Peer 1842f00530bfSEdwin Peer link_info->req_link_speed = fw_speed; 1843532262baSEdwin Peer link_info->req_signal_mode = sig_mode; 1844f00530bfSEdwin Peer link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 1845f00530bfSEdwin Peer link_info->autoneg = 0; 1846f00530bfSEdwin Peer link_info->advertising = 0; 1847532262baSEdwin Peer link_info->advertising_pam4 = 0; 1848f00530bfSEdwin Peer 1849f00530bfSEdwin Peer return 0; 1850c0c050c5SMichael Chan } 1851c0c050c5SMichael Chan 1852939f7f0cSMichael Chan u16 bnxt_get_fw_auto_link_speeds(u32 advertising) 1853c0c050c5SMichael Chan { 1854c0c050c5SMichael Chan u16 fw_speed_mask = 0; 1855c0c050c5SMichael Chan 1856c0c050c5SMichael Chan /* only support autoneg at speed 100, 1000, and 10000 */ 1857c0c050c5SMichael Chan if (advertising & (ADVERTISED_100baseT_Full | 1858c0c050c5SMichael Chan ADVERTISED_100baseT_Half)) { 1859c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 1860c0c050c5SMichael Chan } 1861c0c050c5SMichael Chan if (advertising & (ADVERTISED_1000baseT_Full | 1862c0c050c5SMichael Chan ADVERTISED_1000baseT_Half)) { 1863c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 1864c0c050c5SMichael Chan } 1865c0c050c5SMichael Chan if (advertising & ADVERTISED_10000baseT_Full) 1866c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 1867c0c050c5SMichael Chan 18681c49c421SMichael Chan if (advertising & ADVERTISED_40000baseCR4_Full) 18691c49c421SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18701c49c421SMichael Chan 1871c0c050c5SMichael Chan return fw_speed_mask; 1872c0c050c5SMichael Chan } 1873c0c050c5SMichael Chan 187400c04a92SMichael Chan static int bnxt_set_link_ksettings(struct net_device *dev, 187500c04a92SMichael Chan const struct ethtool_link_ksettings *lk_ksettings) 1876c0c050c5SMichael Chan { 1877c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1878c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 187900c04a92SMichael Chan const struct ethtool_link_settings *base = &lk_ksettings->base; 1880c0c050c5SMichael Chan bool set_pause = false; 188168515a18SMichael Chan u32 speed; 188200c04a92SMichael Chan int rc = 0; 1883c0c050c5SMichael Chan 1884c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 188500c04a92SMichael Chan return -EOPNOTSUPP; 1886c0c050c5SMichael Chan 1887e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 188800c04a92SMichael Chan if (base->autoneg == AUTONEG_ENABLE) { 1889532262baSEdwin Peer link_info->advertising = 0; 1890532262baSEdwin Peer link_info->advertising_pam4 = 0; 1891532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 189200c04a92SMichael Chan advertising); 1893532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 1894532262baSEdwin Peer lk_ksettings, advertising); 1895c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_SPEED; 1896532262baSEdwin Peer if (!link_info->advertising && !link_info->advertising_pam4) { 189793ed8117SMichael Chan link_info->advertising = link_info->support_auto_speeds; 1898532262baSEdwin Peer link_info->advertising_pam4 = 1899532262baSEdwin Peer link_info->support_pam4_auto_speeds; 1900532262baSEdwin Peer } 1901c0c050c5SMichael Chan /* any change to autoneg will cause link change, therefore the 1902c0c050c5SMichael Chan * driver should put back the original pause setting in autoneg 1903c0c050c5SMichael Chan */ 1904c0c050c5SMichael Chan set_pause = true; 1905c0c050c5SMichael Chan } else { 190603efbec0SMichael Chan u8 phy_type = link_info->phy_type; 19079d9cee08SMichael Chan 190803efbec0SMichael Chan if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 190903efbec0SMichael Chan phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 191003efbec0SMichael Chan link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 191103efbec0SMichael Chan netdev_err(dev, "10GBase-T devices must autoneg\n"); 191203efbec0SMichael Chan rc = -EINVAL; 191303efbec0SMichael Chan goto set_setting_exit; 191403efbec0SMichael Chan } 191500c04a92SMichael Chan if (base->duplex == DUPLEX_HALF) { 1916c0c050c5SMichael Chan netdev_err(dev, "HALF DUPLEX is not supported!\n"); 1917c0c050c5SMichael Chan rc = -EINVAL; 1918c0c050c5SMichael Chan goto set_setting_exit; 1919c0c050c5SMichael Chan } 192000c04a92SMichael Chan speed = base->speed; 1921f00530bfSEdwin Peer rc = bnxt_force_link_speed(dev, speed); 1922745b5c65SEdwin Peer if (rc) { 1923745b5c65SEdwin Peer if (rc == -EALREADY) 1924745b5c65SEdwin Peer rc = 0; 19259d9cee08SMichael Chan goto set_setting_exit; 19269d9cee08SMichael Chan } 1927745b5c65SEdwin Peer } 1928c0c050c5SMichael Chan 1929c0c050c5SMichael Chan if (netif_running(dev)) 1930939f7f0cSMichael Chan rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 1931c0c050c5SMichael Chan 1932c0c050c5SMichael Chan set_setting_exit: 1933e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1934c0c050c5SMichael Chan return rc; 1935c0c050c5SMichael Chan } 1936c0c050c5SMichael Chan 19378b277589SMichael Chan static int bnxt_get_fecparam(struct net_device *dev, 19388b277589SMichael Chan struct ethtool_fecparam *fec) 19398b277589SMichael Chan { 19408b277589SMichael Chan struct bnxt *bp = netdev_priv(dev); 19418b277589SMichael Chan struct bnxt_link_info *link_info; 19428b277589SMichael Chan u8 active_fec; 19438b277589SMichael Chan u16 fec_cfg; 19448b277589SMichael Chan 19458b277589SMichael Chan link_info = &bp->link_info; 19468b277589SMichael Chan fec_cfg = link_info->fec_cfg; 19478b277589SMichael Chan active_fec = link_info->active_fec_sig_mode & 19488b277589SMichael Chan PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19498b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 19508b277589SMichael Chan fec->fec = ETHTOOL_FEC_NONE; 19518b277589SMichael Chan fec->active_fec = ETHTOOL_FEC_NONE; 19528b277589SMichael Chan return 0; 19538b277589SMichael Chan } 19548b277589SMichael Chan if (fec_cfg & BNXT_FEC_AUTONEG) 19558b277589SMichael Chan fec->fec |= ETHTOOL_FEC_AUTO; 19568b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19578b277589SMichael Chan fec->fec |= ETHTOOL_FEC_BASER; 19588b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 19598b277589SMichael Chan fec->fec |= ETHTOOL_FEC_RS; 19608b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 19618b277589SMichael Chan fec->fec |= ETHTOOL_FEC_LLRS; 19628b277589SMichael Chan 19638b277589SMichael Chan switch (active_fec) { 19648b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19658b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_BASER; 19668b277589SMichael Chan break; 19678b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19688b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19698b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19708b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_RS; 19718b277589SMichael Chan break; 19728b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19738b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19748b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_LLRS; 19758b277589SMichael Chan break; 197684d3c83eSSomnath Kotur case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 197784d3c83eSSomnath Kotur fec->active_fec |= ETHTOOL_FEC_OFF; 197884d3c83eSSomnath Kotur break; 19798b277589SMichael Chan } 19808b277589SMichael Chan return 0; 19818b277589SMichael Chan } 19828b277589SMichael Chan 1983c9ca5c3aSJakub Kicinski static void bnxt_get_fec_stats(struct net_device *dev, 1984c9ca5c3aSJakub Kicinski struct ethtool_fec_stats *fec_stats) 1985c9ca5c3aSJakub Kicinski { 1986c9ca5c3aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 1987c9ca5c3aSJakub Kicinski u64 *rx; 1988c9ca5c3aSJakub Kicinski 1989c9ca5c3aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 1990c9ca5c3aSJakub Kicinski return; 1991c9ca5c3aSJakub Kicinski 1992c9ca5c3aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 1993c9ca5c3aSJakub Kicinski fec_stats->corrected_bits.total = 1994c9ca5c3aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 1995c9ca5c3aSJakub Kicinski } 1996c9ca5c3aSJakub Kicinski 1997ccd6a9dcSMichael Chan static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 1998ccd6a9dcSMichael Chan u32 fec) 1999ccd6a9dcSMichael Chan { 2000ccd6a9dcSMichael Chan u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 2001ccd6a9dcSMichael Chan 2002ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_BASER) 2003ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 2004ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_RS) 2005ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_RS_ON(link_info); 2006ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_LLRS) 2007ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_LLRS_ON; 2008ccd6a9dcSMichael Chan return fw_fec; 2009ccd6a9dcSMichael Chan } 2010ccd6a9dcSMichael Chan 2011ccd6a9dcSMichael Chan static int bnxt_set_fecparam(struct net_device *dev, 2012ccd6a9dcSMichael Chan struct ethtool_fecparam *fecparam) 2013ccd6a9dcSMichael Chan { 2014bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 2015ccd6a9dcSMichael Chan struct bnxt *bp = netdev_priv(dev); 2016ccd6a9dcSMichael Chan struct bnxt_link_info *link_info; 2017ccd6a9dcSMichael Chan u32 new_cfg, fec = fecparam->fec; 2018ccd6a9dcSMichael Chan u16 fec_cfg; 2019ccd6a9dcSMichael Chan int rc; 2020ccd6a9dcSMichael Chan 2021ccd6a9dcSMichael Chan link_info = &bp->link_info; 2022ccd6a9dcSMichael Chan fec_cfg = link_info->fec_cfg; 2023ccd6a9dcSMichael Chan if (fec_cfg & BNXT_FEC_NONE) 2024ccd6a9dcSMichael Chan return -EOPNOTSUPP; 2025ccd6a9dcSMichael Chan 2026ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_OFF) { 2027ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 2028ccd6a9dcSMichael Chan BNXT_FEC_ALL_OFF(link_info); 2029ccd6a9dcSMichael Chan goto apply_fec; 2030ccd6a9dcSMichael Chan } 2031ccd6a9dcSMichael Chan if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 2032ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 2033ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 2034ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 2035ccd6a9dcSMichael Chan return -EINVAL; 2036ccd6a9dcSMichael Chan 2037ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_AUTO) { 2038ccd6a9dcSMichael Chan if (!link_info->autoneg) 2039ccd6a9dcSMichael Chan return -EINVAL; 2040ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 2041ccd6a9dcSMichael Chan } else { 2042ccd6a9dcSMichael Chan new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 2043ccd6a9dcSMichael Chan } 2044ccd6a9dcSMichael Chan 2045ccd6a9dcSMichael Chan apply_fec: 2046bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 2047bbf33d1dSEdwin Peer if (rc) 2048bbf33d1dSEdwin Peer return rc; 2049bbf33d1dSEdwin Peer req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 2050bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2051ccd6a9dcSMichael Chan /* update current settings */ 2052ccd6a9dcSMichael Chan if (!rc) { 2053ccd6a9dcSMichael Chan mutex_lock(&bp->link_lock); 2054ccd6a9dcSMichael Chan bnxt_update_link(bp, false); 2055ccd6a9dcSMichael Chan mutex_unlock(&bp->link_lock); 2056ccd6a9dcSMichael Chan } 2057ccd6a9dcSMichael Chan return rc; 2058ccd6a9dcSMichael Chan } 2059ccd6a9dcSMichael Chan 2060c0c050c5SMichael Chan static void bnxt_get_pauseparam(struct net_device *dev, 2061c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2062c0c050c5SMichael Chan { 2063c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2064c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2065c0c050c5SMichael Chan 2066c0c050c5SMichael Chan if (BNXT_VF(bp)) 2067c0c050c5SMichael Chan return; 2068b763499eSMichael Chan epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20693c02d1bbSMichael Chan epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20703c02d1bbSMichael Chan epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 2071c0c050c5SMichael Chan } 2072c0c050c5SMichael Chan 2073423cffcfSJakub Kicinski static void bnxt_get_pause_stats(struct net_device *dev, 2074423cffcfSJakub Kicinski struct ethtool_pause_stats *epstat) 2075423cffcfSJakub Kicinski { 2076423cffcfSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2077423cffcfSJakub Kicinski u64 *rx, *tx; 2078423cffcfSJakub Kicinski 2079423cffcfSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 2080423cffcfSJakub Kicinski return; 2081423cffcfSJakub Kicinski 2082423cffcfSJakub Kicinski rx = bp->port_stats.sw_stats; 2083423cffcfSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 2084423cffcfSJakub Kicinski 2085423cffcfSJakub Kicinski epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 2086423cffcfSJakub Kicinski epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 2087423cffcfSJakub Kicinski } 2088423cffcfSJakub Kicinski 2089c0c050c5SMichael Chan static int bnxt_set_pauseparam(struct net_device *dev, 2090c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2091c0c050c5SMichael Chan { 2092c0c050c5SMichael Chan int rc = 0; 2093c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2094c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2095c0c050c5SMichael Chan 2096c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 209775362a3fSMichael Chan return -EOPNOTSUPP; 2098c0c050c5SMichael Chan 2099a5390690SMichael Chan mutex_lock(&bp->link_lock); 2100c0c050c5SMichael Chan if (epause->autoneg) { 2101a5390690SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 2102a5390690SMichael Chan rc = -EINVAL; 2103a5390690SMichael Chan goto pause_exit; 2104a5390690SMichael Chan } 2105b763499eSMichael Chan 2106c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 2107c9ee9516SMichael Chan if (bp->hwrm_spec_code >= 0x10201) 2108c9ee9516SMichael Chan link_info->req_flow_ctrl = 2109c9ee9516SMichael Chan PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE; 2110c0c050c5SMichael Chan } else { 2111c0c050c5SMichael Chan /* when transition from auto pause to force pause, 2112c0c050c5SMichael Chan * force a link change 2113c0c050c5SMichael Chan */ 2114c0c050c5SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 2115c0c050c5SMichael Chan link_info->force_link_chng = true; 2116c0c050c5SMichael Chan link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 2117c9ee9516SMichael Chan link_info->req_flow_ctrl = 0; 2118c0c050c5SMichael Chan } 2119c0c050c5SMichael Chan if (epause->rx_pause) 2120c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 2121c0c050c5SMichael Chan 2122c0c050c5SMichael Chan if (epause->tx_pause) 2123c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 2124c0c050c5SMichael Chan 2125a5390690SMichael Chan if (netif_running(dev)) 2126c0c050c5SMichael Chan rc = bnxt_hwrm_set_pause(bp); 2127a5390690SMichael Chan 2128a5390690SMichael Chan pause_exit: 2129163e9ef6SVasundhara Volam mutex_unlock(&bp->link_lock); 2130c0c050c5SMichael Chan return rc; 2131c0c050c5SMichael Chan } 2132c0c050c5SMichael Chan 2133c0c050c5SMichael Chan static u32 bnxt_get_link(struct net_device *dev) 2134c0c050c5SMichael Chan { 2135c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2136c0c050c5SMichael Chan 2137c0c050c5SMichael Chan /* TODO: handle MF, VF, driver close case */ 2138c0c050c5SMichael Chan return bp->link_info.link_up; 2139c0c050c5SMichael Chan } 2140c0c050c5SMichael Chan 21414933f675SVasundhara Volam int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 21424933f675SVasundhara Volam struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 21434933f675SVasundhara Volam { 2144bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_output *resp; 2145bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_input *req; 21464933f675SVasundhara Volam int rc; 21474933f675SVasundhara Volam 21480ae0a779SVasundhara Volam if (BNXT_VF(bp)) 21490ae0a779SVasundhara Volam return -EOPNOTSUPP; 21500ae0a779SVasundhara Volam 2151bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 2152bbf33d1dSEdwin Peer if (rc) 2153bbf33d1dSEdwin Peer return rc; 2154bbf33d1dSEdwin Peer 2155bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 2156bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 21574933f675SVasundhara Volam if (!rc) 21584933f675SVasundhara Volam memcpy(nvm_dev_info, resp, sizeof(*resp)); 2159bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 21604933f675SVasundhara Volam return rc; 21614933f675SVasundhara Volam } 21624933f675SVasundhara Volam 2163b3b0ddd0SMichael Chan static void bnxt_print_admin_err(struct bnxt *bp) 2164b3b0ddd0SMichael Chan { 2165b3b0ddd0SMichael Chan netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 2166b3b0ddd0SMichael Chan } 2167b3b0ddd0SMichael Chan 21685ac67d8bSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21695ac67d8bSRob Swindell u16 ext, u16 *index, u32 *item_length, 21705ac67d8bSRob Swindell u32 *data_length); 21715ac67d8bSRob Swindell 2172bbf33d1dSEdwin Peer static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 217393ff3435SPavan Chebbi u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 217493ff3435SPavan Chebbi u32 dir_item_len, const u8 *data, 2175c0c050c5SMichael Chan size_t data_len) 2176c0c050c5SMichael Chan { 2177c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2178bbf33d1dSEdwin Peer struct hwrm_nvm_write_input *req; 2179c0c050c5SMichael Chan int rc; 2180c0c050c5SMichael Chan 2181bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 2182bbf33d1dSEdwin Peer if (rc) 2183bbf33d1dSEdwin Peer return rc; 2184c0c050c5SMichael Chan 218593ff3435SPavan Chebbi if (data_len && data) { 2186bbf33d1dSEdwin Peer dma_addr_t dma_handle; 2187bbf33d1dSEdwin Peer u8 *kmem; 2188c0c050c5SMichael Chan 2189bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 2190bbf33d1dSEdwin Peer if (!kmem) { 2191bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2192c0c050c5SMichael Chan return -ENOMEM; 219393ff3435SPavan Chebbi } 2194c0c050c5SMichael Chan 2195bbf33d1dSEdwin Peer req->dir_data_length = cpu_to_le32(data_len); 2196bbf33d1dSEdwin Peer 2197bbf33d1dSEdwin Peer memcpy(kmem, data, data_len); 2198bbf33d1dSEdwin Peer req->host_src_addr = cpu_to_le64(dma_handle); 2199bbf33d1dSEdwin Peer } 2200bbf33d1dSEdwin Peer 2201bce9a0b7SEdwin Peer hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 2202bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(dir_type); 2203bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(dir_ordinal); 2204bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(dir_ext); 2205bbf33d1dSEdwin Peer req->dir_attr = cpu_to_le16(dir_attr); 2206bbf33d1dSEdwin Peer req->dir_item_length = cpu_to_le32(dir_item_len); 2207bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2208c0c050c5SMichael Chan 2209d4f1420dSMichael Chan if (rc == -EACCES) 2210b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2211c0c050c5SMichael Chan return rc; 2212c0c050c5SMichael Chan } 2213c0c050c5SMichael Chan 22148f6c5e4dSEdwin Peer int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 221595fec034SEdwin Peer u8 self_reset, u8 flags) 2216d2d6318cSRob Swindell { 22177c675421SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 2218bbf33d1dSEdwin Peer struct hwrm_fw_reset_input *req; 22197c675421SVasundhara Volam int rc; 2220d2d6318cSRob Swindell 2221892a662fSEdwin Peer if (!bnxt_hwrm_reset_permitted(bp)) { 2222892a662fSEdwin Peer netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 2223892a662fSEdwin Peer return -EPERM; 2224892a662fSEdwin Peer } 2225892a662fSEdwin Peer 2226bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 2227bbf33d1dSEdwin Peer if (rc) 2228bbf33d1dSEdwin Peer return rc; 2229d2d6318cSRob Swindell 2230bbf33d1dSEdwin Peer req->embedded_proc_type = proc_type; 2231bbf33d1dSEdwin Peer req->selfrst_status = self_reset; 2232bbf33d1dSEdwin Peer req->flags = flags; 223395fec034SEdwin Peer 22348cec0940SEdwin Peer if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 2235bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 22368cec0940SEdwin Peer } else { 2237bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 223895fec034SEdwin Peer if (rc == -EACCES) 223995fec034SEdwin Peer bnxt_print_admin_err(bp); 22408cec0940SEdwin Peer } 224195fec034SEdwin Peer return rc; 224295fec034SEdwin Peer } 224395fec034SEdwin Peer 224494f17e89SEdwin Peer static int bnxt_firmware_reset(struct net_device *dev, 224594f17e89SEdwin Peer enum bnxt_nvm_directory_type dir_type) 224695fec034SEdwin Peer { 224795fec034SEdwin Peer u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 224895fec034SEdwin Peer u8 proc_type, flags = 0; 224995fec034SEdwin Peer 2250d2d6318cSRob Swindell /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 2251d2d6318cSRob Swindell /* (e.g. when firmware isn't already running) */ 2252d2d6318cSRob Swindell switch (dir_type) { 2253d2d6318cSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 2254d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE: 2255d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE_2: 225695fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 2257d2d6318cSRob Swindell /* Self-reset ChiMP upon next PCIe reset: */ 225895fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2259d2d6318cSRob Swindell break; 2260d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_FW: 2261d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 226295fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 226308141e0bSRob Swindell /* Self-reset APE upon next PCIe reset: */ 226495fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2265d2d6318cSRob Swindell break; 2266d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_FW: 2267d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 226895fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 2269d2d6318cSRob Swindell break; 2270d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_FW: 2271d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 227295fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 2273d2d6318cSRob Swindell break; 2274d2d6318cSRob Swindell default: 2275d2d6318cSRob Swindell return -EINVAL; 2276d2d6318cSRob Swindell } 2277d2d6318cSRob Swindell 227895fec034SEdwin Peer return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 2279d2d6318cSRob Swindell } 2280d2d6318cSRob Swindell 228194f17e89SEdwin Peer static int bnxt_firmware_reset_chip(struct net_device *dev) 228294f17e89SEdwin Peer { 228394f17e89SEdwin Peer struct bnxt *bp = netdev_priv(dev); 228494f17e89SEdwin Peer u8 flags = 0; 228594f17e89SEdwin Peer 228694f17e89SEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 228794f17e89SEdwin Peer flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 228894f17e89SEdwin Peer 228994f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, 229094f17e89SEdwin Peer FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 229194f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 229294f17e89SEdwin Peer flags); 229394f17e89SEdwin Peer } 229494f17e89SEdwin Peer 229594f17e89SEdwin Peer static int bnxt_firmware_reset_ap(struct net_device *dev) 229694f17e89SEdwin Peer { 229794f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 229894f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 229994f17e89SEdwin Peer 0); 230094f17e89SEdwin Peer } 230194f17e89SEdwin Peer 2302c0c050c5SMichael Chan static int bnxt_flash_firmware(struct net_device *dev, 2303c0c050c5SMichael Chan u16 dir_type, 2304c0c050c5SMichael Chan const u8 *fw_data, 2305c0c050c5SMichael Chan size_t fw_size) 2306c0c050c5SMichael Chan { 2307c0c050c5SMichael Chan int rc = 0; 2308c0c050c5SMichael Chan u16 code_type; 2309c0c050c5SMichael Chan u32 stored_crc; 2310c0c050c5SMichael Chan u32 calculated_crc; 2311c0c050c5SMichael Chan struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 2312c0c050c5SMichael Chan 2313c0c050c5SMichael Chan switch (dir_type) { 2314c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2315c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2316c0c050c5SMichael Chan code_type = CODE_BOOT; 2317c0c050c5SMichael Chan break; 231893e0b4feSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 231993e0b4feSRob Swindell code_type = CODE_CHIMP_PATCH; 232093e0b4feSRob Swindell break; 23212731d70fSRob Swindell case BNX_DIR_TYPE_APE_FW: 23222731d70fSRob Swindell code_type = CODE_MCTP_PASSTHRU; 23232731d70fSRob Swindell break; 232493e0b4feSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 232593e0b4feSRob Swindell code_type = CODE_APE_PATCH; 232693e0b4feSRob Swindell break; 232793e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_FW: 232893e0b4feSRob Swindell code_type = CODE_KONG_FW; 232993e0b4feSRob Swindell break; 233093e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 233193e0b4feSRob Swindell code_type = CODE_KONG_PATCH; 233293e0b4feSRob Swindell break; 233393e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 233493e0b4feSRob Swindell code_type = CODE_BONO_FW; 233593e0b4feSRob Swindell break; 233693e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 233793e0b4feSRob Swindell code_type = CODE_BONO_PATCH; 233893e0b4feSRob Swindell break; 2339c0c050c5SMichael Chan default: 2340c0c050c5SMichael Chan netdev_err(dev, "Unsupported directory entry type: %u\n", 2341c0c050c5SMichael Chan dir_type); 2342c0c050c5SMichael Chan return -EINVAL; 2343c0c050c5SMichael Chan } 2344c0c050c5SMichael Chan if (fw_size < sizeof(struct bnxt_fw_header)) { 2345c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware file size: %u\n", 2346c0c050c5SMichael Chan (unsigned int)fw_size); 2347c0c050c5SMichael Chan return -EINVAL; 2348c0c050c5SMichael Chan } 2349c0c050c5SMichael Chan if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 2350c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware signature: %08X\n", 2351c0c050c5SMichael Chan le32_to_cpu(header->signature)); 2352c0c050c5SMichael Chan return -EINVAL; 2353c0c050c5SMichael Chan } 2354c0c050c5SMichael Chan if (header->code_type != code_type) { 2355c0c050c5SMichael Chan netdev_err(dev, "Expected firmware type: %d, read: %d\n", 2356c0c050c5SMichael Chan code_type, header->code_type); 2357c0c050c5SMichael Chan return -EINVAL; 2358c0c050c5SMichael Chan } 2359c0c050c5SMichael Chan if (header->device != DEVICE_CUMULUS_FAMILY) { 2360c0c050c5SMichael Chan netdev_err(dev, "Expected firmware device family %d, read: %d\n", 2361c0c050c5SMichael Chan DEVICE_CUMULUS_FAMILY, header->device); 2362c0c050c5SMichael Chan return -EINVAL; 2363c0c050c5SMichael Chan } 2364c0c050c5SMichael Chan /* Confirm the CRC32 checksum of the file: */ 2365c0c050c5SMichael Chan stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 2366c0c050c5SMichael Chan sizeof(stored_crc))); 2367c0c050c5SMichael Chan calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 2368c0c050c5SMichael Chan if (calculated_crc != stored_crc) { 2369c0c050c5SMichael Chan netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 2370c0c050c5SMichael Chan (unsigned long)stored_crc, 2371c0c050c5SMichael Chan (unsigned long)calculated_crc); 2372c0c050c5SMichael Chan return -EINVAL; 2373c0c050c5SMichael Chan } 2374c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2375bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 2376d2d6318cSRob Swindell if (rc == 0) /* Firmware update successful */ 2377d2d6318cSRob Swindell rc = bnxt_firmware_reset(dev, dir_type); 2378d2d6318cSRob Swindell 2379c0c050c5SMichael Chan return rc; 2380c0c050c5SMichael Chan } 2381c0c050c5SMichael Chan 23825ac67d8bSRob Swindell static int bnxt_flash_microcode(struct net_device *dev, 23835ac67d8bSRob Swindell u16 dir_type, 23845ac67d8bSRob Swindell const u8 *fw_data, 23855ac67d8bSRob Swindell size_t fw_size) 23865ac67d8bSRob Swindell { 23875ac67d8bSRob Swindell struct bnxt_ucode_trailer *trailer; 23885ac67d8bSRob Swindell u32 calculated_crc; 23895ac67d8bSRob Swindell u32 stored_crc; 23905ac67d8bSRob Swindell int rc = 0; 23915ac67d8bSRob Swindell 23925ac67d8bSRob Swindell if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 23935ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode file size: %u\n", 23945ac67d8bSRob Swindell (unsigned int)fw_size); 23955ac67d8bSRob Swindell return -EINVAL; 23965ac67d8bSRob Swindell } 23975ac67d8bSRob Swindell trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 23985ac67d8bSRob Swindell sizeof(*trailer))); 23995ac67d8bSRob Swindell if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 24005ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 24015ac67d8bSRob Swindell le32_to_cpu(trailer->sig)); 24025ac67d8bSRob Swindell return -EINVAL; 24035ac67d8bSRob Swindell } 24045ac67d8bSRob Swindell if (le16_to_cpu(trailer->dir_type) != dir_type) { 24055ac67d8bSRob Swindell netdev_err(dev, "Expected microcode type: %d, read: %d\n", 24065ac67d8bSRob Swindell dir_type, le16_to_cpu(trailer->dir_type)); 24075ac67d8bSRob Swindell return -EINVAL; 24085ac67d8bSRob Swindell } 24095ac67d8bSRob Swindell if (le16_to_cpu(trailer->trailer_length) < 24105ac67d8bSRob Swindell sizeof(struct bnxt_ucode_trailer)) { 24115ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer length: %d\n", 24125ac67d8bSRob Swindell le16_to_cpu(trailer->trailer_length)); 24135ac67d8bSRob Swindell return -EINVAL; 24145ac67d8bSRob Swindell } 24155ac67d8bSRob Swindell 24165ac67d8bSRob Swindell /* Confirm the CRC32 checksum of the file: */ 24175ac67d8bSRob Swindell stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 24185ac67d8bSRob Swindell sizeof(stored_crc))); 24195ac67d8bSRob Swindell calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 24205ac67d8bSRob Swindell if (calculated_crc != stored_crc) { 24215ac67d8bSRob Swindell netdev_err(dev, 24225ac67d8bSRob Swindell "CRC32 (%08lX) does not match calculated: %08lX\n", 24235ac67d8bSRob Swindell (unsigned long)stored_crc, 24245ac67d8bSRob Swindell (unsigned long)calculated_crc); 24255ac67d8bSRob Swindell return -EINVAL; 24265ac67d8bSRob Swindell } 24275ac67d8bSRob Swindell rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2428bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 24295ac67d8bSRob Swindell 24305ac67d8bSRob Swindell return rc; 24315ac67d8bSRob Swindell } 24325ac67d8bSRob Swindell 2433c0c050c5SMichael Chan static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 2434c0c050c5SMichael Chan { 2435c0c050c5SMichael Chan switch (dir_type) { 2436c0c050c5SMichael Chan case BNX_DIR_TYPE_CHIMP_PATCH: 2437c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2438c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2439c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_FW: 2440c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_PATCH: 2441c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_FW: 2442c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_PATCH: 244393e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 244493e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 2445c0c050c5SMichael Chan return true; 2446c0c050c5SMichael Chan } 2447c0c050c5SMichael Chan 2448c0c050c5SMichael Chan return false; 2449c0c050c5SMichael Chan } 2450c0c050c5SMichael Chan 24515ac67d8bSRob Swindell static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 2452c0c050c5SMichael Chan { 2453c0c050c5SMichael Chan switch (dir_type) { 2454c0c050c5SMichael Chan case BNX_DIR_TYPE_AVS: 2455c0c050c5SMichael Chan case BNX_DIR_TYPE_EXP_ROM_MBA: 2456c0c050c5SMichael Chan case BNX_DIR_TYPE_PCIE: 2457c0c050c5SMichael Chan case BNX_DIR_TYPE_TSCF_UCODE: 2458c0c050c5SMichael Chan case BNX_DIR_TYPE_EXT_PHY: 2459c0c050c5SMichael Chan case BNX_DIR_TYPE_CCM: 2460c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT: 2461c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 2462c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 2463c0c050c5SMichael Chan return true; 2464c0c050c5SMichael Chan } 2465c0c050c5SMichael Chan 2466c0c050c5SMichael Chan return false; 2467c0c050c5SMichael Chan } 2468c0c050c5SMichael Chan 2469c0c050c5SMichael Chan static bool bnxt_dir_type_is_executable(u16 dir_type) 2470c0c050c5SMichael Chan { 2471c0c050c5SMichael Chan return bnxt_dir_type_is_ape_bin_format(dir_type) || 24725ac67d8bSRob Swindell bnxt_dir_type_is_other_exec_format(dir_type); 2473c0c050c5SMichael Chan } 2474c0c050c5SMichael Chan 2475c0c050c5SMichael Chan static int bnxt_flash_firmware_from_file(struct net_device *dev, 2476c0c050c5SMichael Chan u16 dir_type, 2477c0c050c5SMichael Chan const char *filename) 2478c0c050c5SMichael Chan { 2479c0c050c5SMichael Chan const struct firmware *fw; 2480c0c050c5SMichael Chan int rc; 2481c0c050c5SMichael Chan 2482c0c050c5SMichael Chan rc = request_firmware(&fw, filename, &dev->dev); 2483c0c050c5SMichael Chan if (rc != 0) { 2484c0c050c5SMichael Chan netdev_err(dev, "Error %d requesting firmware file: %s\n", 2485c0c050c5SMichael Chan rc, filename); 2486c0c050c5SMichael Chan return rc; 2487c0c050c5SMichael Chan } 2488ba425800SJason Yan if (bnxt_dir_type_is_ape_bin_format(dir_type)) 2489c0c050c5SMichael Chan rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 2490ba425800SJason Yan else if (bnxt_dir_type_is_other_exec_format(dir_type)) 24915ac67d8bSRob Swindell rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 2492c0c050c5SMichael Chan else 2493c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2494bbf33d1dSEdwin Peer 0, 0, 0, fw->data, fw->size); 2495c0c050c5SMichael Chan release_firmware(fw); 2496c0c050c5SMichael Chan return rc; 2497c0c050c5SMichael Chan } 2498c0c050c5SMichael Chan 2499a86b313eSMichael Chan #define BNXT_PKG_DMA_SIZE 0x40000 2500a86b313eSMichael Chan #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 2501a86b313eSMichael Chan #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 2502a86b313eSMichael Chan 2503b44cfd4fSJacob Keller int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 2504d168f328SVasundhara Volam u32 install_type) 2505c0c050c5SMichael Chan { 2506bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_input *install; 2507bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_output *resp; 2508bbf33d1dSEdwin Peer struct hwrm_nvm_modify_input *modify; 2509a9094ba6SMichael Chan struct bnxt *bp = netdev_priv(dev); 25101432c3f6SPavan Chebbi bool defrag_attempted = false; 2511a9094ba6SMichael Chan dma_addr_t dma_handle; 2512a9094ba6SMichael Chan u8 *kmem = NULL; 2513a86b313eSMichael Chan u32 modify_len; 25145ac67d8bSRob Swindell u32 item_len; 25158e42aef0SKalesh AP u8 cmd_err; 25165ac67d8bSRob Swindell u16 index; 2517bbf33d1dSEdwin Peer int rc; 25185ac67d8bSRob Swindell 25195ac67d8bSRob Swindell bnxt_hwrm_fw_set_time(bp); 25205ac67d8bSRob Swindell 2521bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 2522bbf33d1dSEdwin Peer if (rc) 2523bbf33d1dSEdwin Peer return rc; 2524a9094ba6SMichael Chan 2525a86b313eSMichael Chan /* Try allocating a large DMA buffer first. Older fw will 2526a86b313eSMichael Chan * cause excessive NVRAM erases when using small blocks. 2527a86b313eSMichael Chan */ 2528a86b313eSMichael Chan modify_len = roundup_pow_of_two(fw->size); 2529a86b313eSMichael Chan modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 2530a86b313eSMichael Chan while (1) { 2531bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 2532a86b313eSMichael Chan if (!kmem && modify_len > PAGE_SIZE) 2533a86b313eSMichael Chan modify_len /= 2; 2534a86b313eSMichael Chan else 2535a86b313eSMichael Chan break; 2536a86b313eSMichael Chan } 2537bbf33d1dSEdwin Peer if (!kmem) { 2538bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2539a9094ba6SMichael Chan return -ENOMEM; 2540bbf33d1dSEdwin Peer } 2541a9094ba6SMichael Chan 2542bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 2543bbf33d1dSEdwin Peer if (rc) { 2544bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2545bbf33d1dSEdwin Peer return rc; 2546bbf33d1dSEdwin Peer } 2547a9094ba6SMichael Chan 2548bce9a0b7SEdwin Peer hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 2549bce9a0b7SEdwin Peer hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 2550bbf33d1dSEdwin Peer 2551bbf33d1dSEdwin Peer hwrm_req_hold(bp, modify); 2552bbf33d1dSEdwin Peer modify->host_src_addr = cpu_to_le64(dma_handle); 2553bbf33d1dSEdwin Peer 2554bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, install); 2555a9094ba6SMichael Chan if ((install_type & 0xffff) == 0) 2556a9094ba6SMichael Chan install_type >>= 16; 2557bbf33d1dSEdwin Peer install->install_type = cpu_to_le32(install_type); 2558a9094ba6SMichael Chan 25592e5fb428SPavan Chebbi do { 2560a86b313eSMichael Chan u32 copied = 0, len = modify_len; 2561a86b313eSMichael Chan 256295ec1f47SVasundhara Volam rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 25632e5fb428SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 25642e5fb428SPavan Chebbi BNX_DIR_EXT_NONE, 256595ec1f47SVasundhara Volam &index, &item_len, NULL); 256695ec1f47SVasundhara Volam if (rc) { 25675ac67d8bSRob Swindell netdev_err(dev, "PKG update area not created in nvram\n"); 25682e5fb428SPavan Chebbi break; 25695ac67d8bSRob Swindell } 25705ac67d8bSRob Swindell if (fw->size > item_len) { 25719a005c38SJonathan Lemon netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", 25725ac67d8bSRob Swindell (unsigned long)fw->size); 25735ac67d8bSRob Swindell rc = -EFBIG; 25742e5fb428SPavan Chebbi break; 25752e5fb428SPavan Chebbi } 25762e5fb428SPavan Chebbi 2577bbf33d1dSEdwin Peer modify->dir_idx = cpu_to_le16(index); 25785ac67d8bSRob Swindell 2579a86b313eSMichael Chan if (fw->size > modify_len) 2580bbf33d1dSEdwin Peer modify->flags = BNXT_NVM_MORE_FLAG; 2581a86b313eSMichael Chan while (copied < fw->size) { 2582a86b313eSMichael Chan u32 balance = fw->size - copied; 2583a86b313eSMichael Chan 2584a86b313eSMichael Chan if (balance <= modify_len) { 2585a86b313eSMichael Chan len = balance; 2586a86b313eSMichael Chan if (copied) 2587bbf33d1dSEdwin Peer modify->flags |= BNXT_NVM_LAST_FLAG; 2588a86b313eSMichael Chan } 2589a86b313eSMichael Chan memcpy(kmem, fw->data + copied, len); 2590bbf33d1dSEdwin Peer modify->len = cpu_to_le32(len); 2591bbf33d1dSEdwin Peer modify->offset = cpu_to_le32(copied); 2592bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, modify); 259322630e28SEdwin Peer if (rc) 2594a86b313eSMichael Chan goto pkg_abort; 2595a86b313eSMichael Chan copied += len; 2596a86b313eSMichael Chan } 2597bbf33d1dSEdwin Peer 2598bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 25998e42aef0SKalesh AP if (!rc) 26008e42aef0SKalesh AP break; 2601cb4d1d62SKshitij Soni 26021432c3f6SPavan Chebbi if (defrag_attempted) { 26031432c3f6SPavan Chebbi /* We have tried to defragment already in the previous 26041432c3f6SPavan Chebbi * iteration. Return with the result for INSTALL_UPDATE 26051432c3f6SPavan Chebbi */ 26061432c3f6SPavan Chebbi break; 26071432c3f6SPavan Chebbi } 26081432c3f6SPavan Chebbi 26098e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 26108e42aef0SKalesh AP 26118e42aef0SKalesh AP switch (cmd_err) { 2612*54ff1e3eSKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: 2613*54ff1e3eSKalesh AP netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure Anti-rollback detected\n"); 2614*54ff1e3eSKalesh AP rc = -EALREADY; 2615*54ff1e3eSKalesh AP break; 26168e42aef0SKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: 2617bbf33d1dSEdwin Peer install->flags = 26182e5fb428SPavan Chebbi cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 26192e5fb428SPavan Chebbi 2620bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 26218e42aef0SKalesh AP if (!rc) 26228e42aef0SKalesh AP break; 26231432c3f6SPavan Chebbi 26248e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 26258e42aef0SKalesh AP 26268e42aef0SKalesh AP if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 26271432c3f6SPavan Chebbi /* FW has cleared NVM area, driver will create 26281432c3f6SPavan Chebbi * UPDATE directory and try the flash again 26291432c3f6SPavan Chebbi */ 26301432c3f6SPavan Chebbi defrag_attempted = true; 2631bbf33d1dSEdwin Peer install->flags = 0; 2632bbf33d1dSEdwin Peer rc = bnxt_flash_nvram(bp->dev, 26331432c3f6SPavan Chebbi BNX_DIR_TYPE_UPDATE, 26341432c3f6SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 2635bbf33d1dSEdwin Peer 0, 0, item_len, NULL, 0); 26368e42aef0SKalesh AP if (!rc) 26378e42aef0SKalesh AP break; 26381432c3f6SPavan Chebbi } 26398e42aef0SKalesh AP fallthrough; 26408e42aef0SKalesh AP default: 26418e42aef0SKalesh AP netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x cmd_err :%x\n", 26428e42aef0SKalesh AP rc, cmd_err); 2643dd2ebf34SVasundhara Volam } 26441432c3f6SPavan Chebbi } while (defrag_attempted && !rc); 26455ac67d8bSRob Swindell 2646a86b313eSMichael Chan pkg_abort: 2647bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2648bbf33d1dSEdwin Peer hwrm_req_drop(bp, install); 2649bbf33d1dSEdwin Peer 2650bbf33d1dSEdwin Peer if (resp->result) { 26515ac67d8bSRob Swindell netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 2652bbf33d1dSEdwin Peer (s8)resp->result, (int)resp->problem_item); 2653cb4d1d62SKshitij Soni rc = -ENOPKG; 26545ac67d8bSRob Swindell } 265522630e28SEdwin Peer if (rc == -EACCES) 2656b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2657cb4d1d62SKshitij Soni return rc; 2658c0c050c5SMichael Chan } 2659c0c050c5SMichael Chan 2660b44cfd4fSJacob Keller static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 2661b44cfd4fSJacob Keller u32 install_type) 2662b44cfd4fSJacob Keller { 2663b44cfd4fSJacob Keller const struct firmware *fw; 2664b44cfd4fSJacob Keller int rc; 2665b44cfd4fSJacob Keller 2666b44cfd4fSJacob Keller rc = request_firmware(&fw, filename, &dev->dev); 2667b44cfd4fSJacob Keller if (rc != 0) { 2668b44cfd4fSJacob Keller netdev_err(dev, "PKG error %d requesting file: %s\n", 2669b44cfd4fSJacob Keller rc, filename); 2670b44cfd4fSJacob Keller return rc; 2671b44cfd4fSJacob Keller } 2672b44cfd4fSJacob Keller 2673b44cfd4fSJacob Keller rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type); 2674b44cfd4fSJacob Keller 2675b44cfd4fSJacob Keller release_firmware(fw); 2676b44cfd4fSJacob Keller 2677b44cfd4fSJacob Keller return rc; 2678b44cfd4fSJacob Keller } 2679b44cfd4fSJacob Keller 2680c0c050c5SMichael Chan static int bnxt_flash_device(struct net_device *dev, 2681c0c050c5SMichael Chan struct ethtool_flash *flash) 2682c0c050c5SMichael Chan { 2683c0c050c5SMichael Chan if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 2684c0c050c5SMichael Chan netdev_err(dev, "flashdev not supported from a virtual function\n"); 2685c0c050c5SMichael Chan return -EINVAL; 2686c0c050c5SMichael Chan } 2687c0c050c5SMichael Chan 26885ac67d8bSRob Swindell if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 26895ac67d8bSRob Swindell flash->region > 0xffff) 26905ac67d8bSRob Swindell return bnxt_flash_package_from_file(dev, flash->data, 26915ac67d8bSRob Swindell flash->region); 2692c0c050c5SMichael Chan 2693c0c050c5SMichael Chan return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 2694c0c050c5SMichael Chan } 2695c0c050c5SMichael Chan 2696c0c050c5SMichael Chan static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 2697c0c050c5SMichael Chan { 2698bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_output *output; 2699bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_input *req; 2700c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2701c0c050c5SMichael Chan int rc; 2702c0c050c5SMichael Chan 2703bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 2704bbf33d1dSEdwin Peer if (rc) 2705bbf33d1dSEdwin Peer return rc; 2706c0c050c5SMichael Chan 2707bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2708bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2709c0c050c5SMichael Chan if (!rc) { 2710c0c050c5SMichael Chan *entries = le32_to_cpu(output->entries); 2711c0c050c5SMichael Chan *length = le32_to_cpu(output->entry_length); 2712c0c050c5SMichael Chan } 2713bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2714c0c050c5SMichael Chan return rc; 2715c0c050c5SMichael Chan } 2716c0c050c5SMichael Chan 2717c0c050c5SMichael Chan static int bnxt_get_eeprom_len(struct net_device *dev) 2718c0c050c5SMichael Chan { 27194cebbacaSMichael Chan struct bnxt *bp = netdev_priv(dev); 27204cebbacaSMichael Chan 27214cebbacaSMichael Chan if (BNXT_VF(bp)) 27224cebbacaSMichael Chan return 0; 27234cebbacaSMichael Chan 2724c0c050c5SMichael Chan /* The -1 return value allows the entire 32-bit range of offsets to be 2725c0c050c5SMichael Chan * passed via the ethtool command-line utility. 2726c0c050c5SMichael Chan */ 2727c0c050c5SMichael Chan return -1; 2728c0c050c5SMichael Chan } 2729c0c050c5SMichael Chan 2730c0c050c5SMichael Chan static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 2731c0c050c5SMichael Chan { 2732c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2733c0c050c5SMichael Chan int rc; 2734c0c050c5SMichael Chan u32 dir_entries; 2735c0c050c5SMichael Chan u32 entry_length; 2736c0c050c5SMichael Chan u8 *buf; 2737c0c050c5SMichael Chan size_t buflen; 2738c0c050c5SMichael Chan dma_addr_t dma_handle; 2739bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_entries_input *req; 2740c0c050c5SMichael Chan 2741c0c050c5SMichael Chan rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 2742c0c050c5SMichael Chan if (rc != 0) 2743c0c050c5SMichael Chan return rc; 2744c0c050c5SMichael Chan 2745dbbfa96aSVasundhara Volam if (!dir_entries || !entry_length) 2746dbbfa96aSVasundhara Volam return -EIO; 2747dbbfa96aSVasundhara Volam 2748c0c050c5SMichael Chan /* Insert 2 bytes of directory info (count and size of entries) */ 2749c0c050c5SMichael Chan if (len < 2) 2750c0c050c5SMichael Chan return -EINVAL; 2751c0c050c5SMichael Chan 2752c0c050c5SMichael Chan *data++ = dir_entries; 2753c0c050c5SMichael Chan *data++ = entry_length; 2754c0c050c5SMichael Chan len -= 2; 2755c0c050c5SMichael Chan memset(data, 0xff, len); 2756c0c050c5SMichael Chan 2757bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 2758bbf33d1dSEdwin Peer if (rc) 2759bbf33d1dSEdwin Peer return rc; 2760bbf33d1dSEdwin Peer 2761c0c050c5SMichael Chan buflen = dir_entries * entry_length; 2762bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 2763c0c050c5SMichael Chan if (!buf) { 2764bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2765c0c050c5SMichael Chan return -ENOMEM; 2766c0c050c5SMichael Chan } 2767bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2768bbf33d1dSEdwin Peer 2769bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2770bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2771c0c050c5SMichael Chan if (rc == 0) 2772c0c050c5SMichael Chan memcpy(data, buf, len > buflen ? buflen : len); 2773bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2774c0c050c5SMichael Chan return rc; 2775c0c050c5SMichael Chan } 2776c0c050c5SMichael Chan 2777c0c050c5SMichael Chan static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 2778c0c050c5SMichael Chan u32 length, u8 *data) 2779c0c050c5SMichael Chan { 2780c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2781c0c050c5SMichael Chan int rc; 2782c0c050c5SMichael Chan u8 *buf; 2783c0c050c5SMichael Chan dma_addr_t dma_handle; 2784bbf33d1dSEdwin Peer struct hwrm_nvm_read_input *req; 2785c0c050c5SMichael Chan 2786e0ad8fc5SMichael Chan if (!length) 2787e0ad8fc5SMichael Chan return -EINVAL; 2788e0ad8fc5SMichael Chan 2789bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 2790bbf33d1dSEdwin Peer if (rc) 2791bbf33d1dSEdwin Peer return rc; 2792bbf33d1dSEdwin Peer 2793bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 2794c0c050c5SMichael Chan if (!buf) { 2795bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2796c0c050c5SMichael Chan return -ENOMEM; 2797c0c050c5SMichael Chan } 2798c0c050c5SMichael Chan 2799bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2800bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2801bbf33d1dSEdwin Peer req->offset = cpu_to_le32(offset); 2802bbf33d1dSEdwin Peer req->len = cpu_to_le32(length); 2803bbf33d1dSEdwin Peer 2804bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2805bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2806c0c050c5SMichael Chan if (rc == 0) 2807c0c050c5SMichael Chan memcpy(data, buf, length); 2808bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2809c0c050c5SMichael Chan return rc; 2810c0c050c5SMichael Chan } 2811c0c050c5SMichael Chan 28123ebf6f0aSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 28133ebf6f0aSRob Swindell u16 ext, u16 *index, u32 *item_length, 28143ebf6f0aSRob Swindell u32 *data_length) 28153ebf6f0aSRob Swindell { 2816bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_output *output; 2817bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_input *req; 28183ebf6f0aSRob Swindell struct bnxt *bp = netdev_priv(dev); 28193ebf6f0aSRob Swindell int rc; 28203ebf6f0aSRob Swindell 2821bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 2822bbf33d1dSEdwin Peer if (rc) 2823bbf33d1dSEdwin Peer return rc; 2824bbf33d1dSEdwin Peer 2825bbf33d1dSEdwin Peer req->enables = 0; 2826bbf33d1dSEdwin Peer req->dir_idx = 0; 2827bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(type); 2828bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(ordinal); 2829bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(ext); 2830bbf33d1dSEdwin Peer req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 2831bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2832bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 28333ebf6f0aSRob Swindell if (rc == 0) { 28343ebf6f0aSRob Swindell if (index) 28353ebf6f0aSRob Swindell *index = le16_to_cpu(output->dir_idx); 28363ebf6f0aSRob Swindell if (item_length) 28373ebf6f0aSRob Swindell *item_length = le32_to_cpu(output->dir_item_length); 28383ebf6f0aSRob Swindell if (data_length) 28393ebf6f0aSRob Swindell *data_length = le32_to_cpu(output->dir_data_length); 28403ebf6f0aSRob Swindell } 2841bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 28423ebf6f0aSRob Swindell return rc; 28433ebf6f0aSRob Swindell } 28443ebf6f0aSRob Swindell 28453ebf6f0aSRob Swindell static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 28463ebf6f0aSRob Swindell { 28473ebf6f0aSRob Swindell char *retval = NULL; 28483ebf6f0aSRob Swindell char *p; 28493ebf6f0aSRob Swindell char *value; 28503ebf6f0aSRob Swindell int field = 0; 28513ebf6f0aSRob Swindell 28523ebf6f0aSRob Swindell if (datalen < 1) 28533ebf6f0aSRob Swindell return NULL; 28543ebf6f0aSRob Swindell /* null-terminate the log data (removing last '\n'): */ 28553ebf6f0aSRob Swindell data[datalen - 1] = 0; 28563ebf6f0aSRob Swindell for (p = data; *p != 0; p++) { 28573ebf6f0aSRob Swindell field = 0; 28583ebf6f0aSRob Swindell retval = NULL; 28593ebf6f0aSRob Swindell while (*p != 0 && *p != '\n') { 28603ebf6f0aSRob Swindell value = p; 28613ebf6f0aSRob Swindell while (*p != 0 && *p != '\t' && *p != '\n') 28623ebf6f0aSRob Swindell p++; 28633ebf6f0aSRob Swindell if (field == desired_field) 28643ebf6f0aSRob Swindell retval = value; 28653ebf6f0aSRob Swindell if (*p != '\t') 28663ebf6f0aSRob Swindell break; 28673ebf6f0aSRob Swindell *p = 0; 28683ebf6f0aSRob Swindell field++; 28693ebf6f0aSRob Swindell p++; 28703ebf6f0aSRob Swindell } 28713ebf6f0aSRob Swindell if (*p == 0) 28723ebf6f0aSRob Swindell break; 28733ebf6f0aSRob Swindell *p = 0; 28743ebf6f0aSRob Swindell } 28753ebf6f0aSRob Swindell return retval; 28763ebf6f0aSRob Swindell } 28773ebf6f0aSRob Swindell 287863185eb3SVikas Gupta int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 28793ebf6f0aSRob Swindell { 2880a60faa60SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 28813ebf6f0aSRob Swindell u16 index = 0; 2882a60faa60SVasundhara Volam char *pkgver; 2883a60faa60SVasundhara Volam u32 pkglen; 2884a60faa60SVasundhara Volam u8 *pkgbuf; 288563185eb3SVikas Gupta int rc; 28863ebf6f0aSRob Swindell 288763185eb3SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 28883ebf6f0aSRob Swindell BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 288963185eb3SVikas Gupta &index, NULL, &pkglen); 289063185eb3SVikas Gupta if (rc) 289163185eb3SVikas Gupta return rc; 28923ebf6f0aSRob Swindell 2893a60faa60SVasundhara Volam pkgbuf = kzalloc(pkglen, GFP_KERNEL); 2894a60faa60SVasundhara Volam if (!pkgbuf) { 2895a60faa60SVasundhara Volam dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 2896a60faa60SVasundhara Volam pkglen); 289763185eb3SVikas Gupta return -ENOMEM; 2898a60faa60SVasundhara Volam } 28993ebf6f0aSRob Swindell 290063185eb3SVikas Gupta rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 290163185eb3SVikas Gupta if (rc) 2902a60faa60SVasundhara Volam goto err; 2903a60faa60SVasundhara Volam 2904a60faa60SVasundhara Volam pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 2905a60faa60SVasundhara Volam pkglen); 290663185eb3SVikas Gupta if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 290763185eb3SVikas Gupta strscpy(ver, pkgver, size); 290863185eb3SVikas Gupta else 290963185eb3SVikas Gupta rc = -ENOENT; 291063185eb3SVikas Gupta 2911a60faa60SVasundhara Volam err: 2912a60faa60SVasundhara Volam kfree(pkgbuf); 291363185eb3SVikas Gupta 291463185eb3SVikas Gupta return rc; 291563185eb3SVikas Gupta } 291663185eb3SVikas Gupta 291763185eb3SVikas Gupta static void bnxt_get_pkgver(struct net_device *dev) 291863185eb3SVikas Gupta { 291963185eb3SVikas Gupta struct bnxt *bp = netdev_priv(dev); 292063185eb3SVikas Gupta char buf[FW_VER_STR_LEN]; 292163185eb3SVikas Gupta int len; 292263185eb3SVikas Gupta 292363185eb3SVikas Gupta if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 292463185eb3SVikas Gupta len = strlen(bp->fw_ver_str); 292563185eb3SVikas Gupta snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 292663185eb3SVikas Gupta "/pkg %s", buf); 292763185eb3SVikas Gupta } 29283ebf6f0aSRob Swindell } 29293ebf6f0aSRob Swindell 2930c0c050c5SMichael Chan static int bnxt_get_eeprom(struct net_device *dev, 2931c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 2932c0c050c5SMichael Chan u8 *data) 2933c0c050c5SMichael Chan { 2934c0c050c5SMichael Chan u32 index; 2935c0c050c5SMichael Chan u32 offset; 2936c0c050c5SMichael Chan 2937c0c050c5SMichael Chan if (eeprom->offset == 0) /* special offset value to get directory */ 2938c0c050c5SMichael Chan return bnxt_get_nvram_directory(dev, eeprom->len, data); 2939c0c050c5SMichael Chan 2940c0c050c5SMichael Chan index = eeprom->offset >> 24; 2941c0c050c5SMichael Chan offset = eeprom->offset & 0xffffff; 2942c0c050c5SMichael Chan 2943c0c050c5SMichael Chan if (index == 0) { 2944c0c050c5SMichael Chan netdev_err(dev, "unsupported index value: %d\n", index); 2945c0c050c5SMichael Chan return -EINVAL; 2946c0c050c5SMichael Chan } 2947c0c050c5SMichael Chan 2948c0c050c5SMichael Chan return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 2949c0c050c5SMichael Chan } 2950c0c050c5SMichael Chan 2951c0c050c5SMichael Chan static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 2952c0c050c5SMichael Chan { 2953bbf33d1dSEdwin Peer struct hwrm_nvm_erase_dir_entry_input *req; 2954c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2955bbf33d1dSEdwin Peer int rc; 2956c0c050c5SMichael Chan 2957bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 2958bbf33d1dSEdwin Peer if (rc) 2959bbf33d1dSEdwin Peer return rc; 2960bbf33d1dSEdwin Peer 2961bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2962bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 2963c0c050c5SMichael Chan } 2964c0c050c5SMichael Chan 2965c0c050c5SMichael Chan static int bnxt_set_eeprom(struct net_device *dev, 2966c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 2967c0c050c5SMichael Chan u8 *data) 2968c0c050c5SMichael Chan { 2969c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2970c0c050c5SMichael Chan u8 index, dir_op; 2971c0c050c5SMichael Chan u16 type, ext, ordinal, attr; 2972c0c050c5SMichael Chan 2973c0c050c5SMichael Chan if (!BNXT_PF(bp)) { 2974c0c050c5SMichael Chan netdev_err(dev, "NVM write not supported from a virtual function\n"); 2975c0c050c5SMichael Chan return -EINVAL; 2976c0c050c5SMichael Chan } 2977c0c050c5SMichael Chan 2978c0c050c5SMichael Chan type = eeprom->magic >> 16; 2979c0c050c5SMichael Chan 2980c0c050c5SMichael Chan if (type == 0xffff) { /* special value for directory operations */ 2981c0c050c5SMichael Chan index = eeprom->magic & 0xff; 2982c0c050c5SMichael Chan dir_op = eeprom->magic >> 8; 2983c0c050c5SMichael Chan if (index == 0) 2984c0c050c5SMichael Chan return -EINVAL; 2985c0c050c5SMichael Chan switch (dir_op) { 2986c0c050c5SMichael Chan case 0x0e: /* erase */ 2987c0c050c5SMichael Chan if (eeprom->offset != ~eeprom->magic) 2988c0c050c5SMichael Chan return -EINVAL; 2989c0c050c5SMichael Chan return bnxt_erase_nvram_directory(dev, index - 1); 2990c0c050c5SMichael Chan default: 2991c0c050c5SMichael Chan return -EINVAL; 2992c0c050c5SMichael Chan } 2993c0c050c5SMichael Chan } 2994c0c050c5SMichael Chan 2995c0c050c5SMichael Chan /* Create or re-write an NVM item: */ 2996ba425800SJason Yan if (bnxt_dir_type_is_executable(type)) 29975ac67d8bSRob Swindell return -EOPNOTSUPP; 2998c0c050c5SMichael Chan ext = eeprom->magic & 0xffff; 2999c0c050c5SMichael Chan ordinal = eeprom->offset >> 16; 3000c0c050c5SMichael Chan attr = eeprom->offset & 0xffff; 3001c0c050c5SMichael Chan 3002bbf33d1dSEdwin Peer return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 3003c0c050c5SMichael Chan eeprom->len); 3004c0c050c5SMichael Chan } 3005c0c050c5SMichael Chan 300672b34f04SMichael Chan static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 300772b34f04SMichael Chan { 300872b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 300972b34f04SMichael Chan struct ethtool_eee *eee = &bp->eee; 301072b34f04SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 3011a5390690SMichael Chan u32 advertising; 301272b34f04SMichael Chan int rc = 0; 301372b34f04SMichael Chan 3014c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 301575362a3fSMichael Chan return -EOPNOTSUPP; 301672b34f04SMichael Chan 3017b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 301872b34f04SMichael Chan return -EOPNOTSUPP; 301972b34f04SMichael Chan 3020a5390690SMichael Chan mutex_lock(&bp->link_lock); 3021a5390690SMichael Chan advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 302272b34f04SMichael Chan if (!edata->eee_enabled) 302372b34f04SMichael Chan goto eee_ok; 302472b34f04SMichael Chan 302572b34f04SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 302672b34f04SMichael Chan netdev_warn(dev, "EEE requires autoneg\n"); 3027a5390690SMichael Chan rc = -EINVAL; 3028a5390690SMichael Chan goto eee_exit; 302972b34f04SMichael Chan } 303072b34f04SMichael Chan if (edata->tx_lpi_enabled) { 303172b34f04SMichael Chan if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 303272b34f04SMichael Chan edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 303372b34f04SMichael Chan netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 303472b34f04SMichael Chan bp->lpi_tmr_lo, bp->lpi_tmr_hi); 3035a5390690SMichael Chan rc = -EINVAL; 3036a5390690SMichael Chan goto eee_exit; 303772b34f04SMichael Chan } else if (!bp->lpi_tmr_hi) { 303872b34f04SMichael Chan edata->tx_lpi_timer = eee->tx_lpi_timer; 303972b34f04SMichael Chan } 304072b34f04SMichael Chan } 304172b34f04SMichael Chan if (!edata->advertised) { 304272b34f04SMichael Chan edata->advertised = advertising & eee->supported; 304372b34f04SMichael Chan } else if (edata->advertised & ~advertising) { 304472b34f04SMichael Chan netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 304572b34f04SMichael Chan edata->advertised, advertising); 3046a5390690SMichael Chan rc = -EINVAL; 3047a5390690SMichael Chan goto eee_exit; 304872b34f04SMichael Chan } 304972b34f04SMichael Chan 305072b34f04SMichael Chan eee->advertised = edata->advertised; 305172b34f04SMichael Chan eee->tx_lpi_enabled = edata->tx_lpi_enabled; 305272b34f04SMichael Chan eee->tx_lpi_timer = edata->tx_lpi_timer; 305372b34f04SMichael Chan eee_ok: 305472b34f04SMichael Chan eee->eee_enabled = edata->eee_enabled; 305572b34f04SMichael Chan 305672b34f04SMichael Chan if (netif_running(dev)) 305772b34f04SMichael Chan rc = bnxt_hwrm_set_link_setting(bp, false, true); 305872b34f04SMichael Chan 3059a5390690SMichael Chan eee_exit: 3060a5390690SMichael Chan mutex_unlock(&bp->link_lock); 306172b34f04SMichael Chan return rc; 306272b34f04SMichael Chan } 306372b34f04SMichael Chan 306472b34f04SMichael Chan static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 306572b34f04SMichael Chan { 306672b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 306772b34f04SMichael Chan 3068b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 306972b34f04SMichael Chan return -EOPNOTSUPP; 307072b34f04SMichael Chan 307172b34f04SMichael Chan *edata = bp->eee; 307272b34f04SMichael Chan if (!bp->eee.eee_enabled) { 307372b34f04SMichael Chan /* Preserve tx_lpi_timer so that the last value will be used 307472b34f04SMichael Chan * by default when it is re-enabled. 307572b34f04SMichael Chan */ 307672b34f04SMichael Chan edata->advertised = 0; 307772b34f04SMichael Chan edata->tx_lpi_enabled = 0; 307872b34f04SMichael Chan } 307972b34f04SMichael Chan 308072b34f04SMichael Chan if (!bp->eee.eee_active) 308172b34f04SMichael Chan edata->lp_advertised = 0; 308272b34f04SMichael Chan 308372b34f04SMichael Chan return 0; 308472b34f04SMichael Chan } 308572b34f04SMichael Chan 308642ee18feSAjit Khaparde static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 308742ee18feSAjit Khaparde u16 page_number, u16 start_addr, 308842ee18feSAjit Khaparde u16 data_length, u8 *buf) 308942ee18feSAjit Khaparde { 3090bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_output *output; 3091bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_input *req; 309242ee18feSAjit Khaparde int rc, byte_offset = 0; 309342ee18feSAjit Khaparde 3094bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 3095bbf33d1dSEdwin Peer if (rc) 3096bbf33d1dSEdwin Peer return rc; 3097bbf33d1dSEdwin Peer 3098bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 3099bbf33d1dSEdwin Peer req->i2c_slave_addr = i2c_addr; 3100bbf33d1dSEdwin Peer req->page_number = cpu_to_le16(page_number); 3101bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(bp->pf.port_id); 310242ee18feSAjit Khaparde do { 310342ee18feSAjit Khaparde u16 xfer_size; 310442ee18feSAjit Khaparde 310542ee18feSAjit Khaparde xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 310642ee18feSAjit Khaparde data_length -= xfer_size; 3107bbf33d1dSEdwin Peer req->page_offset = cpu_to_le16(start_addr + byte_offset); 3108bbf33d1dSEdwin Peer req->data_length = xfer_size; 3109bbf33d1dSEdwin Peer req->enables = cpu_to_le32(start_addr + byte_offset ? 311042ee18feSAjit Khaparde PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); 3111bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 311242ee18feSAjit Khaparde if (!rc) 311342ee18feSAjit Khaparde memcpy(buf + byte_offset, output->data, xfer_size); 311442ee18feSAjit Khaparde byte_offset += xfer_size; 311542ee18feSAjit Khaparde } while (!rc && data_length > 0); 3116bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 311742ee18feSAjit Khaparde 311842ee18feSAjit Khaparde return rc; 311942ee18feSAjit Khaparde } 312042ee18feSAjit Khaparde 312142ee18feSAjit Khaparde static int bnxt_get_module_info(struct net_device *dev, 312242ee18feSAjit Khaparde struct ethtool_modinfo *modinfo) 312342ee18feSAjit Khaparde { 31247328a23cSVasundhara Volam u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 312542ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 312642ee18feSAjit Khaparde int rc; 312742ee18feSAjit Khaparde 312842ee18feSAjit Khaparde /* No point in going further if phy status indicates 312942ee18feSAjit Khaparde * module is not inserted or if it is powered down or 313042ee18feSAjit Khaparde * if it is of type 10GBase-T 313142ee18feSAjit Khaparde */ 313242ee18feSAjit Khaparde if (bp->link_info.module_status > 313342ee18feSAjit Khaparde PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 313442ee18feSAjit Khaparde return -EOPNOTSUPP; 313542ee18feSAjit Khaparde 313642ee18feSAjit Khaparde /* This feature is not supported in older firmware versions */ 313742ee18feSAjit Khaparde if (bp->hwrm_spec_code < 0x10202) 313842ee18feSAjit Khaparde return -EOPNOTSUPP; 313942ee18feSAjit Khaparde 31407328a23cSVasundhara Volam rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 31417328a23cSVasundhara Volam SFF_DIAG_SUPPORT_OFFSET + 1, 31427328a23cSVasundhara Volam data); 314342ee18feSAjit Khaparde if (!rc) { 31447328a23cSVasundhara Volam u8 module_id = data[0]; 31457328a23cSVasundhara Volam u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 314642ee18feSAjit Khaparde 314742ee18feSAjit Khaparde switch (module_id) { 314842ee18feSAjit Khaparde case SFF_MODULE_ID_SFP: 314942ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8472; 315042ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 31517328a23cSVasundhara Volam if (!diag_supported) 31527328a23cSVasundhara Volam modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 315342ee18feSAjit Khaparde break; 315442ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP: 315542ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP_PLUS: 315642ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8436; 315742ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 315842ee18feSAjit Khaparde break; 315942ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP28: 316042ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8636; 316142ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 316242ee18feSAjit Khaparde break; 316342ee18feSAjit Khaparde default: 316442ee18feSAjit Khaparde rc = -EOPNOTSUPP; 316542ee18feSAjit Khaparde break; 316642ee18feSAjit Khaparde } 316742ee18feSAjit Khaparde } 316842ee18feSAjit Khaparde return rc; 316942ee18feSAjit Khaparde } 317042ee18feSAjit Khaparde 317142ee18feSAjit Khaparde static int bnxt_get_module_eeprom(struct net_device *dev, 317242ee18feSAjit Khaparde struct ethtool_eeprom *eeprom, 317342ee18feSAjit Khaparde u8 *data) 317442ee18feSAjit Khaparde { 317542ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 317642ee18feSAjit Khaparde u16 start = eeprom->offset, length = eeprom->len; 3177f3ea3119SColin Ian King int rc = 0; 317842ee18feSAjit Khaparde 317942ee18feSAjit Khaparde memset(data, 0, eeprom->len); 318042ee18feSAjit Khaparde 318142ee18feSAjit Khaparde /* Read A0 portion of the EEPROM */ 318242ee18feSAjit Khaparde if (start < ETH_MODULE_SFF_8436_LEN) { 318342ee18feSAjit Khaparde if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 318442ee18feSAjit Khaparde length = ETH_MODULE_SFF_8436_LEN - start; 318542ee18feSAjit Khaparde rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 318642ee18feSAjit Khaparde start, length, data); 318742ee18feSAjit Khaparde if (rc) 318842ee18feSAjit Khaparde return rc; 318942ee18feSAjit Khaparde start += length; 319042ee18feSAjit Khaparde data += length; 319142ee18feSAjit Khaparde length = eeprom->len - length; 319242ee18feSAjit Khaparde } 319342ee18feSAjit Khaparde 319442ee18feSAjit Khaparde /* Read A2 portion of the EEPROM */ 319542ee18feSAjit Khaparde if (length) { 319642ee18feSAjit Khaparde start -= ETH_MODULE_SFF_8436_LEN; 31974260330bSEdwin Peer rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 3198dea521a2SChristophe JAILLET start, length, data); 319942ee18feSAjit Khaparde } 320042ee18feSAjit Khaparde return rc; 320142ee18feSAjit Khaparde } 320242ee18feSAjit Khaparde 3203ae8e98a6SDeepak Khungar static int bnxt_nway_reset(struct net_device *dev) 3204ae8e98a6SDeepak Khungar { 3205ae8e98a6SDeepak Khungar int rc = 0; 3206ae8e98a6SDeepak Khungar 3207ae8e98a6SDeepak Khungar struct bnxt *bp = netdev_priv(dev); 3208ae8e98a6SDeepak Khungar struct bnxt_link_info *link_info = &bp->link_info; 3209ae8e98a6SDeepak Khungar 3210c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 3211ae8e98a6SDeepak Khungar return -EOPNOTSUPP; 3212ae8e98a6SDeepak Khungar 3213ae8e98a6SDeepak Khungar if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 3214ae8e98a6SDeepak Khungar return -EINVAL; 3215ae8e98a6SDeepak Khungar 3216ae8e98a6SDeepak Khungar if (netif_running(dev)) 3217ae8e98a6SDeepak Khungar rc = bnxt_hwrm_set_link_setting(bp, true, false); 3218ae8e98a6SDeepak Khungar 3219ae8e98a6SDeepak Khungar return rc; 3220ae8e98a6SDeepak Khungar } 3221ae8e98a6SDeepak Khungar 32225ad2cbeeSMichael Chan static int bnxt_set_phys_id(struct net_device *dev, 32235ad2cbeeSMichael Chan enum ethtool_phys_id_state state) 32245ad2cbeeSMichael Chan { 3225bbf33d1dSEdwin Peer struct hwrm_port_led_cfg_input *req; 32265ad2cbeeSMichael Chan struct bnxt *bp = netdev_priv(dev); 32275ad2cbeeSMichael Chan struct bnxt_pf_info *pf = &bp->pf; 32285ad2cbeeSMichael Chan struct bnxt_led_cfg *led_cfg; 32295ad2cbeeSMichael Chan u8 led_state; 32305ad2cbeeSMichael Chan __le16 duration; 3231bbf33d1dSEdwin Peer int rc, i; 32325ad2cbeeSMichael Chan 32335ad2cbeeSMichael Chan if (!bp->num_leds || BNXT_VF(bp)) 32345ad2cbeeSMichael Chan return -EOPNOTSUPP; 32355ad2cbeeSMichael Chan 32365ad2cbeeSMichael Chan if (state == ETHTOOL_ID_ACTIVE) { 32375ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 32385ad2cbeeSMichael Chan duration = cpu_to_le16(500); 32395ad2cbeeSMichael Chan } else if (state == ETHTOOL_ID_INACTIVE) { 32405ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 32415ad2cbeeSMichael Chan duration = cpu_to_le16(0); 32425ad2cbeeSMichael Chan } else { 32435ad2cbeeSMichael Chan return -EINVAL; 32445ad2cbeeSMichael Chan } 3245bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 3246bbf33d1dSEdwin Peer if (rc) 3247bbf33d1dSEdwin Peer return rc; 3248bbf33d1dSEdwin Peer 3249bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(pf->port_id); 3250bbf33d1dSEdwin Peer req->num_leds = bp->num_leds; 3251bbf33d1dSEdwin Peer led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 32525ad2cbeeSMichael Chan for (i = 0; i < bp->num_leds; i++, led_cfg++) { 3253bbf33d1dSEdwin Peer req->enables |= BNXT_LED_DFLT_ENABLES(i); 32545ad2cbeeSMichael Chan led_cfg->led_id = bp->leds[i].led_id; 32555ad2cbeeSMichael Chan led_cfg->led_state = led_state; 32565ad2cbeeSMichael Chan led_cfg->led_blink_on = duration; 32575ad2cbeeSMichael Chan led_cfg->led_blink_off = duration; 32585ad2cbeeSMichael Chan led_cfg->led_group_id = bp->leds[i].led_group_id; 32595ad2cbeeSMichael Chan } 3260bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 32615ad2cbeeSMichael Chan } 32625ad2cbeeSMichael Chan 326367fea463SMichael Chan static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 326467fea463SMichael Chan { 3265bbf33d1dSEdwin Peer struct hwrm_selftest_irq_input *req; 3266bbf33d1dSEdwin Peer int rc; 326767fea463SMichael Chan 3268bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 3269bbf33d1dSEdwin Peer if (rc) 3270bbf33d1dSEdwin Peer return rc; 3271bbf33d1dSEdwin Peer 3272bbf33d1dSEdwin Peer req->cmpl_ring = cpu_to_le16(cmpl_ring); 3273bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 327467fea463SMichael Chan } 327567fea463SMichael Chan 327667fea463SMichael Chan static int bnxt_test_irq(struct bnxt *bp) 327767fea463SMichael Chan { 327867fea463SMichael Chan int i; 327967fea463SMichael Chan 328067fea463SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 328167fea463SMichael Chan u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 328267fea463SMichael Chan int rc; 328367fea463SMichael Chan 328467fea463SMichael Chan rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 328567fea463SMichael Chan if (rc) 328667fea463SMichael Chan return rc; 328767fea463SMichael Chan } 328867fea463SMichael Chan return 0; 328967fea463SMichael Chan } 329067fea463SMichael Chan 3291f7dc1ea6SMichael Chan static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 3292f7dc1ea6SMichael Chan { 3293bbf33d1dSEdwin Peer struct hwrm_port_mac_cfg_input *req; 3294bbf33d1dSEdwin Peer int rc; 3295f7dc1ea6SMichael Chan 3296bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 3297bbf33d1dSEdwin Peer if (rc) 3298bbf33d1dSEdwin Peer return rc; 3299f7dc1ea6SMichael Chan 3300bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 3301f7dc1ea6SMichael Chan if (enable) 3302bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 3303f7dc1ea6SMichael Chan else 3304bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 3305bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3306f7dc1ea6SMichael Chan } 3307f7dc1ea6SMichael Chan 330856d37462SVasundhara Volam static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 330956d37462SVasundhara Volam { 3310bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_output *resp; 3311bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_input *req; 331256d37462SVasundhara Volam int rc; 331356d37462SVasundhara Volam 3314bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 3315bbf33d1dSEdwin Peer if (rc) 3316bbf33d1dSEdwin Peer return rc; 3317bbf33d1dSEdwin Peer 3318bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3319bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 332056d37462SVasundhara Volam if (!rc) 332156d37462SVasundhara Volam *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 332256d37462SVasundhara Volam 3323bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 332456d37462SVasundhara Volam return rc; 332556d37462SVasundhara Volam } 332656d37462SVasundhara Volam 332791725d89SMichael Chan static int bnxt_disable_an_for_lpbk(struct bnxt *bp, 332891725d89SMichael Chan struct hwrm_port_phy_cfg_input *req) 332991725d89SMichael Chan { 333091725d89SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 333156d37462SVasundhara Volam u16 fw_advertising; 333291725d89SMichael Chan u16 fw_speed; 333391725d89SMichael Chan int rc; 333491725d89SMichael Chan 33358a60efd1SMichael Chan if (!link_info->autoneg || 3336b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 333791725d89SMichael Chan return 0; 333891725d89SMichael Chan 333956d37462SVasundhara Volam rc = bnxt_query_force_speeds(bp, &fw_advertising); 334056d37462SVasundhara Volam if (rc) 334156d37462SVasundhara Volam return rc; 334256d37462SVasundhara Volam 334391725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 334483d8f5e9SMichael Chan if (bp->link_info.link_up) 334591725d89SMichael Chan fw_speed = bp->link_info.link_speed; 334691725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 334791725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 334891725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 334991725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 335091725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 335191725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 335291725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 335391725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 335491725d89SMichael Chan 335591725d89SMichael Chan req->force_link_speed = cpu_to_le16(fw_speed); 335691725d89SMichael Chan req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 335791725d89SMichael Chan PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 3358bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 335991725d89SMichael Chan req->flags = 0; 336091725d89SMichael Chan req->force_link_speed = cpu_to_le16(0); 336191725d89SMichael Chan return rc; 336291725d89SMichael Chan } 336391725d89SMichael Chan 336455fd0cf3SMichael Chan static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 336591725d89SMichael Chan { 3366bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 3367bbf33d1dSEdwin Peer int rc; 336891725d89SMichael Chan 3369bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 3370bbf33d1dSEdwin Peer if (rc) 3371bbf33d1dSEdwin Peer return rc; 3372bbf33d1dSEdwin Peer 3373bbf33d1dSEdwin Peer /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 3374bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 337591725d89SMichael Chan 337691725d89SMichael Chan if (enable) { 3377bbf33d1dSEdwin Peer bnxt_disable_an_for_lpbk(bp, req); 337855fd0cf3SMichael Chan if (ext) 3379bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 338055fd0cf3SMichael Chan else 3381bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 338291725d89SMichael Chan } else { 3383bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 338491725d89SMichael Chan } 3385bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 3386bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3387bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3388bbf33d1dSEdwin Peer return rc; 338991725d89SMichael Chan } 339091725d89SMichael Chan 3391e44758b7SMichael Chan static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3392f7dc1ea6SMichael Chan u32 raw_cons, int pkt_size) 3393f7dc1ea6SMichael Chan { 3394e44758b7SMichael Chan struct bnxt_napi *bnapi = cpr->bnapi; 3395e44758b7SMichael Chan struct bnxt_rx_ring_info *rxr; 3396f7dc1ea6SMichael Chan struct bnxt_sw_rx_bd *rx_buf; 3397f7dc1ea6SMichael Chan struct rx_cmp *rxcmp; 3398f7dc1ea6SMichael Chan u16 cp_cons, cons; 3399f7dc1ea6SMichael Chan u8 *data; 3400f7dc1ea6SMichael Chan u32 len; 3401f7dc1ea6SMichael Chan int i; 3402f7dc1ea6SMichael Chan 3403e44758b7SMichael Chan rxr = bnapi->rx_ring; 3404f7dc1ea6SMichael Chan cp_cons = RING_CMP(raw_cons); 3405f7dc1ea6SMichael Chan rxcmp = (struct rx_cmp *) 3406f7dc1ea6SMichael Chan &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 3407f7dc1ea6SMichael Chan cons = rxcmp->rx_cmp_opaque; 3408f7dc1ea6SMichael Chan rx_buf = &rxr->rx_buf_ring[cons]; 3409f7dc1ea6SMichael Chan data = rx_buf->data_ptr; 3410f7dc1ea6SMichael Chan len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 3411f7dc1ea6SMichael Chan if (len != pkt_size) 3412f7dc1ea6SMichael Chan return -EIO; 3413f7dc1ea6SMichael Chan i = ETH_ALEN; 3414f7dc1ea6SMichael Chan if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 3415f7dc1ea6SMichael Chan return -EIO; 3416f7dc1ea6SMichael Chan i += ETH_ALEN; 3417f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) { 3418f7dc1ea6SMichael Chan if (data[i] != (u8)(i & 0xff)) 3419f7dc1ea6SMichael Chan return -EIO; 3420f7dc1ea6SMichael Chan } 3421f7dc1ea6SMichael Chan return 0; 3422f7dc1ea6SMichael Chan } 3423f7dc1ea6SMichael Chan 3424e44758b7SMichael Chan static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3425e44758b7SMichael Chan int pkt_size) 3426f7dc1ea6SMichael Chan { 3427f7dc1ea6SMichael Chan struct tx_cmp *txcmp; 3428f7dc1ea6SMichael Chan int rc = -EIO; 3429f7dc1ea6SMichael Chan u32 raw_cons; 3430f7dc1ea6SMichael Chan u32 cons; 3431f7dc1ea6SMichael Chan int i; 3432f7dc1ea6SMichael Chan 3433f7dc1ea6SMichael Chan raw_cons = cpr->cp_raw_cons; 3434f7dc1ea6SMichael Chan for (i = 0; i < 200; i++) { 3435f7dc1ea6SMichael Chan cons = RING_CMP(raw_cons); 3436f7dc1ea6SMichael Chan txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 3437f7dc1ea6SMichael Chan 3438f7dc1ea6SMichael Chan if (!TX_CMP_VALID(txcmp, raw_cons)) { 3439f7dc1ea6SMichael Chan udelay(5); 3440f7dc1ea6SMichael Chan continue; 3441f7dc1ea6SMichael Chan } 3442f7dc1ea6SMichael Chan 3443f7dc1ea6SMichael Chan /* The valid test of the entry must be done first before 3444f7dc1ea6SMichael Chan * reading any further. 3445f7dc1ea6SMichael Chan */ 3446f7dc1ea6SMichael Chan dma_rmb(); 3447f7dc1ea6SMichael Chan if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 3448e44758b7SMichael Chan rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 3449f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3450f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3451f7dc1ea6SMichael Chan break; 3452f7dc1ea6SMichael Chan } 3453f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3454f7dc1ea6SMichael Chan } 3455f7dc1ea6SMichael Chan cpr->cp_raw_cons = raw_cons; 3456f7dc1ea6SMichael Chan return rc; 3457f7dc1ea6SMichael Chan } 3458f7dc1ea6SMichael Chan 3459f7dc1ea6SMichael Chan static int bnxt_run_loopback(struct bnxt *bp) 3460f7dc1ea6SMichael Chan { 3461f7dc1ea6SMichael Chan struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 346284404d5fSMichael Chan struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 3463e44758b7SMichael Chan struct bnxt_cp_ring_info *cpr; 3464f7dc1ea6SMichael Chan int pkt_size, i = 0; 3465f7dc1ea6SMichael Chan struct sk_buff *skb; 3466f7dc1ea6SMichael Chan dma_addr_t map; 3467f7dc1ea6SMichael Chan u8 *data; 3468f7dc1ea6SMichael Chan int rc; 3469f7dc1ea6SMichael Chan 347084404d5fSMichael Chan cpr = &rxr->bnapi->cp_ring; 347184404d5fSMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 347284404d5fSMichael Chan cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 3473f7dc1ea6SMichael Chan pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 3474f7dc1ea6SMichael Chan skb = netdev_alloc_skb(bp->dev, pkt_size); 3475f7dc1ea6SMichael Chan if (!skb) 3476f7dc1ea6SMichael Chan return -ENOMEM; 3477f7dc1ea6SMichael Chan data = skb_put(skb, pkt_size); 3478cfcab3b3SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3479f7dc1ea6SMichael Chan i += ETH_ALEN; 3480f7dc1ea6SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3481f7dc1ea6SMichael Chan i += ETH_ALEN; 3482f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) 3483f7dc1ea6SMichael Chan data[i] = (u8)(i & 0xff); 3484f7dc1ea6SMichael Chan 3485f7dc1ea6SMichael Chan map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 3486df70303dSChristophe JAILLET DMA_TO_DEVICE); 3487f7dc1ea6SMichael Chan if (dma_mapping_error(&bp->pdev->dev, map)) { 3488f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3489f7dc1ea6SMichael Chan return -EIO; 3490f7dc1ea6SMichael Chan } 3491c1ba92a8SMichael Chan bnxt_xmit_bd(bp, txr, map, pkt_size); 3492f7dc1ea6SMichael Chan 3493f7dc1ea6SMichael Chan /* Sync BD data before updating doorbell */ 3494f7dc1ea6SMichael Chan wmb(); 3495f7dc1ea6SMichael Chan 3496697197e5SMichael Chan bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 3497e44758b7SMichael Chan rc = bnxt_poll_loopback(bp, cpr, pkt_size); 3498f7dc1ea6SMichael Chan 3499df70303dSChristophe JAILLET dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 3500f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3501f7dc1ea6SMichael Chan return rc; 3502f7dc1ea6SMichael Chan } 3503f7dc1ea6SMichael Chan 3504eb513658SMichael Chan static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 3505eb513658SMichael Chan { 3506bbf33d1dSEdwin Peer struct hwrm_selftest_exec_output *resp; 3507bbf33d1dSEdwin Peer struct hwrm_selftest_exec_input *req; 3508eb513658SMichael Chan int rc; 3509eb513658SMichael Chan 3510bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 3511bbf33d1dSEdwin Peer if (rc) 3512bbf33d1dSEdwin Peer return rc; 3513bbf33d1dSEdwin Peer 3514bbf33d1dSEdwin Peer hwrm_req_timeout(bp, req, bp->test_info->timeout); 3515bbf33d1dSEdwin Peer req->flags = test_mask; 3516bbf33d1dSEdwin Peer 3517bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3518bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3519eb513658SMichael Chan *test_results = resp->test_success; 3520bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3521eb513658SMichael Chan return rc; 3522eb513658SMichael Chan } 3523eb513658SMichael Chan 352455fd0cf3SMichael Chan #define BNXT_DRV_TESTS 4 3525f7dc1ea6SMichael Chan #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 352691725d89SMichael Chan #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 352755fd0cf3SMichael Chan #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 352855fd0cf3SMichael Chan #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 3529eb513658SMichael Chan 3530eb513658SMichael Chan static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 3531eb513658SMichael Chan u64 *buf) 3532eb513658SMichael Chan { 3533eb513658SMichael Chan struct bnxt *bp = netdev_priv(dev); 353455fd0cf3SMichael Chan bool do_ext_lpbk = false; 3535eb513658SMichael Chan bool offline = false; 3536eb513658SMichael Chan u8 test_results = 0; 3537eb513658SMichael Chan u8 test_mask = 0; 3538d27e2ca1SMichael Chan int rc = 0, i; 3539eb513658SMichael Chan 35406896cb35SVasundhara Volam if (!bp->num_tests || !BNXT_PF(bp)) 3541eb513658SMichael Chan return; 3542eb513658SMichael Chan memset(buf, 0, sizeof(u64) * bp->num_tests); 3543eb513658SMichael Chan if (!netif_running(dev)) { 3544eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3545eb513658SMichael Chan return; 3546eb513658SMichael Chan } 3547eb513658SMichael Chan 354855fd0cf3SMichael Chan if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 3549b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 355055fd0cf3SMichael Chan do_ext_lpbk = true; 355155fd0cf3SMichael Chan 3552eb513658SMichael Chan if (etest->flags & ETH_TEST_FL_OFFLINE) { 35536896cb35SVasundhara Volam if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 3554eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 35556896cb35SVasundhara Volam netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 3556eb513658SMichael Chan return; 3557eb513658SMichael Chan } 3558eb513658SMichael Chan offline = true; 3559eb513658SMichael Chan } 3560eb513658SMichael Chan 3561eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3562eb513658SMichael Chan u8 bit_val = 1 << i; 3563eb513658SMichael Chan 3564eb513658SMichael Chan if (!(bp->test_info->offline_mask & bit_val)) 3565eb513658SMichael Chan test_mask |= bit_val; 3566eb513658SMichael Chan else if (offline) 3567eb513658SMichael Chan test_mask |= bit_val; 3568eb513658SMichael Chan } 3569eb513658SMichael Chan if (!offline) { 3570eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3571eb513658SMichael Chan } else { 35726758f937SMichael Chan bnxt_ulp_stop(bp); 35736758f937SMichael Chan rc = bnxt_close_nic(bp, true, false); 35746758f937SMichael Chan if (rc) { 35756758f937SMichael Chan bnxt_ulp_start(bp, rc); 3576eb513658SMichael Chan return; 35776758f937SMichael Chan } 3578eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3579f7dc1ea6SMichael Chan 3580f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 1; 3581f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, true); 3582f7dc1ea6SMichael Chan msleep(250); 3583f7dc1ea6SMichael Chan rc = bnxt_half_open_nic(bp); 3584f7dc1ea6SMichael Chan if (rc) { 3585f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 3586f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 35876758f937SMichael Chan bnxt_ulp_start(bp, rc); 3588f7dc1ea6SMichael Chan return; 3589f7dc1ea6SMichael Chan } 3590f7dc1ea6SMichael Chan if (bnxt_run_loopback(bp)) 3591f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3592f7dc1ea6SMichael Chan else 3593f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 0; 3594f7dc1ea6SMichael Chan 3595f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 359655fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, false); 359791725d89SMichael Chan msleep(1000); 359891725d89SMichael Chan if (bnxt_run_loopback(bp)) { 359991725d89SMichael Chan buf[BNXT_PHYLPBK_TEST_IDX] = 1; 360091725d89SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 360191725d89SMichael Chan } 360255fd0cf3SMichael Chan if (do_ext_lpbk) { 360355fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 360455fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, true); 360555fd0cf3SMichael Chan msleep(1000); 360655fd0cf3SMichael Chan if (bnxt_run_loopback(bp)) { 360755fd0cf3SMichael Chan buf[BNXT_EXTLPBK_TEST_IDX] = 1; 360855fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 360955fd0cf3SMichael Chan } 361055fd0cf3SMichael Chan } 361155fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, false, false); 361291725d89SMichael Chan bnxt_half_close_nic(bp); 36136758f937SMichael Chan rc = bnxt_open_nic(bp, true, true); 36146758f937SMichael Chan bnxt_ulp_start(bp, rc); 3615eb513658SMichael Chan } 3616d27e2ca1SMichael Chan if (rc || bnxt_test_irq(bp)) { 361767fea463SMichael Chan buf[BNXT_IRQ_TEST_IDX] = 1; 361867fea463SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 361967fea463SMichael Chan } 3620eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3621eb513658SMichael Chan u8 bit_val = 1 << i; 3622eb513658SMichael Chan 3623eb513658SMichael Chan if ((test_mask & bit_val) && !(test_results & bit_val)) { 3624eb513658SMichael Chan buf[i] = 1; 3625eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3626eb513658SMichael Chan } 3627eb513658SMichael Chan } 3628eb513658SMichael Chan } 3629eb513658SMichael Chan 363049f7972fSVasundhara Volam static int bnxt_reset(struct net_device *dev, u32 *flags) 363149f7972fSVasundhara Volam { 363249f7972fSVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36338cec0940SEdwin Peer bool reload = false; 36347a13240eSEdwin Peer u32 req = *flags; 36357a13240eSEdwin Peer 36367a13240eSEdwin Peer if (!req) 36377a13240eSEdwin Peer return -EINVAL; 363849f7972fSVasundhara Volam 363949f7972fSVasundhara Volam if (!BNXT_PF(bp)) { 364049f7972fSVasundhara Volam netdev_err(dev, "Reset is not supported from a VF\n"); 364149f7972fSVasundhara Volam return -EOPNOTSUPP; 364249f7972fSVasundhara Volam } 364349f7972fSVasundhara Volam 36440a3f4e4fSVasundhara Volam if (pci_vfs_assigned(bp->pdev) && 36450a3f4e4fSVasundhara Volam !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 364649f7972fSVasundhara Volam netdev_err(dev, 364749f7972fSVasundhara Volam "Reset not allowed when VFs are assigned to VMs\n"); 364849f7972fSVasundhara Volam return -EBUSY; 364949f7972fSVasundhara Volam } 365049f7972fSVasundhara Volam 36517a13240eSEdwin Peer if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 365249f7972fSVasundhara Volam /* This feature is not supported in older firmware versions */ 36537a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 36547a13240eSEdwin Peer if (!bnxt_firmware_reset_chip(dev)) { 36557a13240eSEdwin Peer netdev_info(dev, "Firmware reset request successful.\n"); 36560a3f4e4fSVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 36578cec0940SEdwin Peer reload = true; 36587a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_CHIP; 36592373d8d6SScott Branden } 36607a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_CHIP) { 36617a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 36627a13240eSEdwin Peer } 36637a13240eSEdwin Peer } 36647a13240eSEdwin Peer 36657a13240eSEdwin Peer if (req & BNXT_FW_RESET_AP) { 36666502ad59SScott Branden /* This feature is not supported in older firmware versions */ 36677a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 36687a13240eSEdwin Peer if (!bnxt_firmware_reset_ap(dev)) { 36697a13240eSEdwin Peer netdev_info(dev, "Reset application processor successful.\n"); 36708cec0940SEdwin Peer reload = true; 36717a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_AP; 36722373d8d6SScott Branden } 36737a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_AP) { 36747a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 36757a13240eSEdwin Peer } 367649f7972fSVasundhara Volam } 367749f7972fSVasundhara Volam 36788cec0940SEdwin Peer if (reload) 36798cec0940SEdwin Peer netdev_info(dev, "Reload driver to complete reset\n"); 36808cec0940SEdwin Peer 36817a13240eSEdwin Peer return 0; 368249f7972fSVasundhara Volam } 368349f7972fSVasundhara Volam 36840b0eacf3SVasundhara Volam static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 36850b0eacf3SVasundhara Volam { 36860b0eacf3SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36870b0eacf3SVasundhara Volam 36880b0eacf3SVasundhara Volam if (dump->flag > BNXT_DUMP_CRASH) { 36890b0eacf3SVasundhara Volam netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 36900b0eacf3SVasundhara Volam return -EINVAL; 36910b0eacf3SVasundhara Volam } 36920b0eacf3SVasundhara Volam 36930b0eacf3SVasundhara Volam if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 36940b0eacf3SVasundhara Volam netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 36950b0eacf3SVasundhara Volam return -EOPNOTSUPP; 36960b0eacf3SVasundhara Volam } 36970b0eacf3SVasundhara Volam 36980b0eacf3SVasundhara Volam bp->dump_flag = dump->flag; 36990b0eacf3SVasundhara Volam return 0; 37000b0eacf3SVasundhara Volam } 37010b0eacf3SVasundhara Volam 37026c5657d0SVasundhara Volam static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 37036c5657d0SVasundhara Volam { 37046c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37056c5657d0SVasundhara Volam 37066c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 37076c5657d0SVasundhara Volam return -EOPNOTSUPP; 37086c5657d0SVasundhara Volam 37096c5657d0SVasundhara Volam dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 37106c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_min_8b << 16 | 37116c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_bld_8b << 8 | 37126c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_rsvd_8b; 37136c5657d0SVasundhara Volam 37140b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 37159a575c8cSEdwin Peer dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 37160b0eacf3SVasundhara Volam return 0; 37176c5657d0SVasundhara Volam } 37186c5657d0SVasundhara Volam 37196c5657d0SVasundhara Volam static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 37206c5657d0SVasundhara Volam void *buf) 37216c5657d0SVasundhara Volam { 37226c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37236c5657d0SVasundhara Volam 37246c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 37256c5657d0SVasundhara Volam return -EOPNOTSUPP; 37266c5657d0SVasundhara Volam 37276c5657d0SVasundhara Volam memset(buf, 0, dump->len); 37286c5657d0SVasundhara Volam 37290b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 37309a575c8cSEdwin Peer return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 37310b0eacf3SVasundhara Volam } 37320b0eacf3SVasundhara Volam 3733118612d5SMichael Chan static int bnxt_get_ts_info(struct net_device *dev, 3734118612d5SMichael Chan struct ethtool_ts_info *info) 3735118612d5SMichael Chan { 3736118612d5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3737118612d5SMichael Chan struct bnxt_ptp_cfg *ptp; 3738118612d5SMichael Chan 3739118612d5SMichael Chan ptp = bp->ptp_cfg; 3740118612d5SMichael Chan info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 3741118612d5SMichael Chan SOF_TIMESTAMPING_RX_SOFTWARE | 3742118612d5SMichael Chan SOF_TIMESTAMPING_SOFTWARE; 3743118612d5SMichael Chan 3744118612d5SMichael Chan info->phc_index = -1; 3745118612d5SMichael Chan if (!ptp) 3746118612d5SMichael Chan return 0; 3747118612d5SMichael Chan 3748118612d5SMichael Chan info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 3749118612d5SMichael Chan SOF_TIMESTAMPING_RX_HARDWARE | 3750118612d5SMichael Chan SOF_TIMESTAMPING_RAW_HARDWARE; 3751118612d5SMichael Chan if (ptp->ptp_clock) 3752118612d5SMichael Chan info->phc_index = ptp_clock_index(ptp->ptp_clock); 3753118612d5SMichael Chan 3754118612d5SMichael Chan info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 3755118612d5SMichael Chan 3756118612d5SMichael Chan info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 3757118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 3758118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 3759118612d5SMichael Chan return 0; 3760118612d5SMichael Chan } 3761118612d5SMichael Chan 3762eb513658SMichael Chan void bnxt_ethtool_init(struct bnxt *bp) 3763eb513658SMichael Chan { 3764bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_output *resp; 3765bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_input *req; 3766eb513658SMichael Chan struct bnxt_test_info *test_info; 3767431aa1ebSMichael Chan struct net_device *dev = bp->dev; 3768eb513658SMichael Chan int i, rc; 3769eb513658SMichael Chan 3770691aa620SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 3771a60faa60SVasundhara Volam bnxt_get_pkgver(dev); 3772431aa1ebSMichael Chan 3773ba642ab7SMichael Chan bp->num_tests = 0; 37746896cb35SVasundhara Volam if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 3775eb513658SMichael Chan return; 3776eb513658SMichael Chan 3777bbf33d1dSEdwin Peer test_info = bp->test_info; 3778bbf33d1dSEdwin Peer if (!test_info) { 3779bbf33d1dSEdwin Peer test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 3780bbf33d1dSEdwin Peer if (!test_info) 3781bbf33d1dSEdwin Peer return; 3782bbf33d1dSEdwin Peer bp->test_info = test_info; 3783bbf33d1dSEdwin Peer } 3784bbf33d1dSEdwin Peer 3785bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 3786bbf33d1dSEdwin Peer return; 3787bbf33d1dSEdwin Peer 3788bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3789bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 3790eb513658SMichael Chan if (rc) 3791eb513658SMichael Chan goto ethtool_init_exit; 3792eb513658SMichael Chan 3793eb513658SMichael Chan bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 3794eb513658SMichael Chan if (bp->num_tests > BNXT_MAX_TEST) 3795eb513658SMichael Chan bp->num_tests = BNXT_MAX_TEST; 3796eb513658SMichael Chan 3797eb513658SMichael Chan test_info->offline_mask = resp->offline_tests; 3798eb513658SMichael Chan test_info->timeout = le16_to_cpu(resp->test_timeout); 3799eb513658SMichael Chan if (!test_info->timeout) 3800eb513658SMichael Chan test_info->timeout = HWRM_CMD_TIMEOUT; 3801eb513658SMichael Chan for (i = 0; i < bp->num_tests; i++) { 3802eb513658SMichael Chan char *str = test_info->string[i]; 3803eb513658SMichael Chan char *fw_str = resp->test0_name + i * 32; 3804eb513658SMichael Chan 3805f7dc1ea6SMichael Chan if (i == BNXT_MACLPBK_TEST_IDX) { 3806f7dc1ea6SMichael Chan strcpy(str, "Mac loopback test (offline)"); 380791725d89SMichael Chan } else if (i == BNXT_PHYLPBK_TEST_IDX) { 380891725d89SMichael Chan strcpy(str, "Phy loopback test (offline)"); 380955fd0cf3SMichael Chan } else if (i == BNXT_EXTLPBK_TEST_IDX) { 381055fd0cf3SMichael Chan strcpy(str, "Ext loopback test (offline)"); 381167fea463SMichael Chan } else if (i == BNXT_IRQ_TEST_IDX) { 381267fea463SMichael Chan strcpy(str, "Interrupt_test (offline)"); 3813f7dc1ea6SMichael Chan } else { 3814eb513658SMichael Chan strlcpy(str, fw_str, ETH_GSTRING_LEN); 3815eb513658SMichael Chan strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); 3816eb513658SMichael Chan if (test_info->offline_mask & (1 << i)) 3817eb513658SMichael Chan strncat(str, " (offline)", 3818eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3819eb513658SMichael Chan else 3820eb513658SMichael Chan strncat(str, " (online)", 3821eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3822eb513658SMichael Chan } 3823f7dc1ea6SMichael Chan } 3824eb513658SMichael Chan 3825eb513658SMichael Chan ethtool_init_exit: 3826bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3827eb513658SMichael Chan } 3828eb513658SMichael Chan 3829782bc00aSJakub Kicinski static void bnxt_get_eth_phy_stats(struct net_device *dev, 3830782bc00aSJakub Kicinski struct ethtool_eth_phy_stats *phy_stats) 3831782bc00aSJakub Kicinski { 3832782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3833782bc00aSJakub Kicinski u64 *rx; 3834782bc00aSJakub Kicinski 3835782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 3836782bc00aSJakub Kicinski return; 3837782bc00aSJakub Kicinski 3838782bc00aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 3839782bc00aSJakub Kicinski phy_stats->SymbolErrorDuringCarrier = 3840782bc00aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 3841782bc00aSJakub Kicinski } 3842782bc00aSJakub Kicinski 3843782bc00aSJakub Kicinski static void bnxt_get_eth_mac_stats(struct net_device *dev, 3844782bc00aSJakub Kicinski struct ethtool_eth_mac_stats *mac_stats) 3845782bc00aSJakub Kicinski { 3846782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3847782bc00aSJakub Kicinski u64 *rx, *tx; 3848782bc00aSJakub Kicinski 3849782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3850782bc00aSJakub Kicinski return; 3851782bc00aSJakub Kicinski 3852782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3853782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3854782bc00aSJakub Kicinski 3855782bc00aSJakub Kicinski mac_stats->FramesReceivedOK = 3856782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 3857782bc00aSJakub Kicinski mac_stats->FramesTransmittedOK = 3858782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 385937434782SJakub Kicinski mac_stats->FrameCheckSequenceErrors = 386037434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 386137434782SJakub Kicinski mac_stats->AlignmentErrors = 386237434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 386337434782SJakub Kicinski mac_stats->OutOfRangeLengthField = 386437434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 3865782bc00aSJakub Kicinski } 3866782bc00aSJakub Kicinski 3867782bc00aSJakub Kicinski static void bnxt_get_eth_ctrl_stats(struct net_device *dev, 3868782bc00aSJakub Kicinski struct ethtool_eth_ctrl_stats *ctrl_stats) 3869782bc00aSJakub Kicinski { 3870782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3871782bc00aSJakub Kicinski u64 *rx; 3872782bc00aSJakub Kicinski 3873782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3874782bc00aSJakub Kicinski return; 3875782bc00aSJakub Kicinski 3876782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3877782bc00aSJakub Kicinski ctrl_stats->MACControlFramesReceived = 3878782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 3879782bc00aSJakub Kicinski } 3880782bc00aSJakub Kicinski 3881782bc00aSJakub Kicinski static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 3882782bc00aSJakub Kicinski { 0, 64 }, 3883782bc00aSJakub Kicinski { 65, 127 }, 3884782bc00aSJakub Kicinski { 128, 255 }, 3885782bc00aSJakub Kicinski { 256, 511 }, 3886782bc00aSJakub Kicinski { 512, 1023 }, 3887782bc00aSJakub Kicinski { 1024, 1518 }, 3888782bc00aSJakub Kicinski { 1519, 2047 }, 3889782bc00aSJakub Kicinski { 2048, 4095 }, 3890782bc00aSJakub Kicinski { 4096, 9216 }, 3891782bc00aSJakub Kicinski { 9217, 16383 }, 3892782bc00aSJakub Kicinski {} 3893782bc00aSJakub Kicinski }; 3894782bc00aSJakub Kicinski 3895782bc00aSJakub Kicinski static void bnxt_get_rmon_stats(struct net_device *dev, 3896782bc00aSJakub Kicinski struct ethtool_rmon_stats *rmon_stats, 3897782bc00aSJakub Kicinski const struct ethtool_rmon_hist_range **ranges) 3898782bc00aSJakub Kicinski { 3899782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3900782bc00aSJakub Kicinski u64 *rx, *tx; 3901782bc00aSJakub Kicinski 3902782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3903782bc00aSJakub Kicinski return; 3904782bc00aSJakub Kicinski 3905782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3906782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3907782bc00aSJakub Kicinski 3908782bc00aSJakub Kicinski rmon_stats->jabbers = 3909782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 3910782bc00aSJakub Kicinski rmon_stats->oversize_pkts = 3911782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 3912782bc00aSJakub Kicinski rmon_stats->undersize_pkts = 3913782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 3914782bc00aSJakub Kicinski 3915782bc00aSJakub Kicinski rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 3916782bc00aSJakub Kicinski rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 3917782bc00aSJakub Kicinski rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 3918782bc00aSJakub Kicinski rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 3919782bc00aSJakub Kicinski rmon_stats->hist[4] = 3920782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 3921782bc00aSJakub Kicinski rmon_stats->hist[5] = 3922782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 3923782bc00aSJakub Kicinski rmon_stats->hist[6] = 3924782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 3925782bc00aSJakub Kicinski rmon_stats->hist[7] = 3926782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 3927782bc00aSJakub Kicinski rmon_stats->hist[8] = 3928782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 3929782bc00aSJakub Kicinski rmon_stats->hist[9] = 3930782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 3931782bc00aSJakub Kicinski 3932782bc00aSJakub Kicinski rmon_stats->hist_tx[0] = 3933782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 3934782bc00aSJakub Kicinski rmon_stats->hist_tx[1] = 3935782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 3936782bc00aSJakub Kicinski rmon_stats->hist_tx[2] = 3937782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 3938782bc00aSJakub Kicinski rmon_stats->hist_tx[3] = 3939782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 3940782bc00aSJakub Kicinski rmon_stats->hist_tx[4] = 3941782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 3942782bc00aSJakub Kicinski rmon_stats->hist_tx[5] = 3943782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 3944782bc00aSJakub Kicinski rmon_stats->hist_tx[6] = 3945782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 3946782bc00aSJakub Kicinski rmon_stats->hist_tx[7] = 3947782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 3948782bc00aSJakub Kicinski rmon_stats->hist_tx[8] = 3949782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 3950782bc00aSJakub Kicinski rmon_stats->hist_tx[9] = 3951782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 3952782bc00aSJakub Kicinski 3953782bc00aSJakub Kicinski *ranges = bnxt_rmon_ranges; 3954782bc00aSJakub Kicinski } 3955782bc00aSJakub Kicinski 3956eb513658SMichael Chan void bnxt_ethtool_free(struct bnxt *bp) 3957eb513658SMichael Chan { 3958eb513658SMichael Chan kfree(bp->test_info); 3959eb513658SMichael Chan bp->test_info = NULL; 3960eb513658SMichael Chan } 3961eb513658SMichael Chan 3962c0c050c5SMichael Chan const struct ethtool_ops bnxt_ethtool_ops = { 3963f704d243SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 3964f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES | 3965f704d243SJakub Kicinski ETHTOOL_COALESCE_USECS_IRQ | 3966f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 3967f704d243SJakub Kicinski ETHTOOL_COALESCE_STATS_BLOCK_USECS | 39683fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 39693fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_CQE, 397000c04a92SMichael Chan .get_link_ksettings = bnxt_get_link_ksettings, 397100c04a92SMichael Chan .set_link_ksettings = bnxt_set_link_ksettings, 3972c9ca5c3aSJakub Kicinski .get_fec_stats = bnxt_get_fec_stats, 39738b277589SMichael Chan .get_fecparam = bnxt_get_fecparam, 3974ccd6a9dcSMichael Chan .set_fecparam = bnxt_set_fecparam, 3975423cffcfSJakub Kicinski .get_pause_stats = bnxt_get_pause_stats, 3976c0c050c5SMichael Chan .get_pauseparam = bnxt_get_pauseparam, 3977c0c050c5SMichael Chan .set_pauseparam = bnxt_set_pauseparam, 3978c0c050c5SMichael Chan .get_drvinfo = bnxt_get_drvinfo, 3979b5d600b0SVasundhara Volam .get_regs_len = bnxt_get_regs_len, 3980b5d600b0SVasundhara Volam .get_regs = bnxt_get_regs, 39818e202366SMichael Chan .get_wol = bnxt_get_wol, 39825282db6cSMichael Chan .set_wol = bnxt_set_wol, 3983c0c050c5SMichael Chan .get_coalesce = bnxt_get_coalesce, 3984c0c050c5SMichael Chan .set_coalesce = bnxt_set_coalesce, 3985c0c050c5SMichael Chan .get_msglevel = bnxt_get_msglevel, 3986c0c050c5SMichael Chan .set_msglevel = bnxt_set_msglevel, 3987c0c050c5SMichael Chan .get_sset_count = bnxt_get_sset_count, 3988c0c050c5SMichael Chan .get_strings = bnxt_get_strings, 3989c0c050c5SMichael Chan .get_ethtool_stats = bnxt_get_ethtool_stats, 3990c0c050c5SMichael Chan .set_ringparam = bnxt_set_ringparam, 3991c0c050c5SMichael Chan .get_ringparam = bnxt_get_ringparam, 3992c0c050c5SMichael Chan .get_channels = bnxt_get_channels, 3993c0c050c5SMichael Chan .set_channels = bnxt_set_channels, 3994c0c050c5SMichael Chan .get_rxnfc = bnxt_get_rxnfc, 3995a011952aSMichael Chan .set_rxnfc = bnxt_set_rxnfc, 3996c0c050c5SMichael Chan .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 3997c0c050c5SMichael Chan .get_rxfh_key_size = bnxt_get_rxfh_key_size, 3998c0c050c5SMichael Chan .get_rxfh = bnxt_get_rxfh, 3999bd3191b5SMichael Chan .set_rxfh = bnxt_set_rxfh, 4000c0c050c5SMichael Chan .flash_device = bnxt_flash_device, 4001c0c050c5SMichael Chan .get_eeprom_len = bnxt_get_eeprom_len, 4002c0c050c5SMichael Chan .get_eeprom = bnxt_get_eeprom, 4003c0c050c5SMichael Chan .set_eeprom = bnxt_set_eeprom, 4004c0c050c5SMichael Chan .get_link = bnxt_get_link, 400572b34f04SMichael Chan .get_eee = bnxt_get_eee, 400672b34f04SMichael Chan .set_eee = bnxt_set_eee, 400742ee18feSAjit Khaparde .get_module_info = bnxt_get_module_info, 400842ee18feSAjit Khaparde .get_module_eeprom = bnxt_get_module_eeprom, 40095ad2cbeeSMichael Chan .nway_reset = bnxt_nway_reset, 40105ad2cbeeSMichael Chan .set_phys_id = bnxt_set_phys_id, 4011eb513658SMichael Chan .self_test = bnxt_self_test, 4012118612d5SMichael Chan .get_ts_info = bnxt_get_ts_info, 401349f7972fSVasundhara Volam .reset = bnxt_reset, 40140b0eacf3SVasundhara Volam .set_dump = bnxt_set_dump, 40156c5657d0SVasundhara Volam .get_dump_flag = bnxt_get_dump_flag, 40166c5657d0SVasundhara Volam .get_dump_data = bnxt_get_dump_data, 4017782bc00aSJakub Kicinski .get_eth_phy_stats = bnxt_get_eth_phy_stats, 4018782bc00aSJakub Kicinski .get_eth_mac_stats = bnxt_get_eth_mac_stats, 4019782bc00aSJakub Kicinski .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 4020782bc00aSJakub Kicinski .get_rmon_stats = bnxt_get_rmon_stats, 4021c0c050c5SMichael Chan }; 4022