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 { 16659a3bc77eSMichael Chan struct bnxt *bp = container_of(link_info, struct bnxt, link_info); 16664b32caccSMichael Chan u16 fw_speeds = link_info->support_speeds; 16674b32caccSMichael Chan 166800c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 1669532262baSEdwin Peer fw_speeds = link_info->support_pam4_speeds; 1670532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16714b32caccSMichael Chan 16729a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) { 16739a3bc77eSMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 16749a3bc77eSMichael Chan Pause); 167500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167600c04a92SMichael Chan Asym_Pause); 16779a3bc77eSMichael Chan } 167893ed8117SMichael Chan 1679532262baSEdwin Peer if (link_info->support_auto_speeds || 1680532262baSEdwin Peer link_info->support_pam4_auto_speeds) 168100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 168200c04a92SMichael Chan Autoneg); 16838b277589SMichael Chan bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 168493ed8117SMichael Chan } 168593ed8117SMichael Chan 1686c0c050c5SMichael Chan u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 1687c0c050c5SMichael Chan { 1688c0c050c5SMichael Chan switch (fw_link_speed) { 1689c0c050c5SMichael Chan case BNXT_LINK_SPEED_100MB: 1690c0c050c5SMichael Chan return SPEED_100; 1691c0c050c5SMichael Chan case BNXT_LINK_SPEED_1GB: 1692c0c050c5SMichael Chan return SPEED_1000; 1693c0c050c5SMichael Chan case BNXT_LINK_SPEED_2_5GB: 1694c0c050c5SMichael Chan return SPEED_2500; 1695c0c050c5SMichael Chan case BNXT_LINK_SPEED_10GB: 1696c0c050c5SMichael Chan return SPEED_10000; 1697c0c050c5SMichael Chan case BNXT_LINK_SPEED_20GB: 1698c0c050c5SMichael Chan return SPEED_20000; 1699c0c050c5SMichael Chan case BNXT_LINK_SPEED_25GB: 1700c0c050c5SMichael Chan return SPEED_25000; 1701c0c050c5SMichael Chan case BNXT_LINK_SPEED_40GB: 1702c0c050c5SMichael Chan return SPEED_40000; 1703c0c050c5SMichael Chan case BNXT_LINK_SPEED_50GB: 1704c0c050c5SMichael Chan return SPEED_50000; 170538a21b34SDeepak Khungar case BNXT_LINK_SPEED_100GB: 170638a21b34SDeepak Khungar return SPEED_100000; 1707c0c050c5SMichael Chan default: 1708c0c050c5SMichael Chan return SPEED_UNKNOWN; 1709c0c050c5SMichael Chan } 1710c0c050c5SMichael Chan } 1711c0c050c5SMichael Chan 171200c04a92SMichael Chan static int bnxt_get_link_ksettings(struct net_device *dev, 171300c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 1714c0c050c5SMichael Chan { 1715c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1716c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 171700c04a92SMichael Chan struct ethtool_link_settings *base = &lk_ksettings->base; 171800c04a92SMichael Chan u32 ethtool_speed; 1719c0c050c5SMichael Chan 172000c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 1721e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 172200c04a92SMichael Chan bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 1723c0c050c5SMichael Chan 172400c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 1725b763499eSMichael Chan if (link_info->autoneg) { 172600c04a92SMichael Chan bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 172700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, 172800c04a92SMichael Chan advertising, Autoneg); 172900c04a92SMichael Chan base->autoneg = AUTONEG_ENABLE; 173000c04a92SMichael Chan base->duplex = DUPLEX_UNKNOWN; 173183d8f5e9SMichael Chan if (link_info->phy_link_status == BNXT_LINK_LINK) { 173283d8f5e9SMichael Chan bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 173383d8f5e9SMichael Chan if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 173400c04a92SMichael Chan base->duplex = DUPLEX_FULL; 173529c262feSMichael Chan else 173600c04a92SMichael Chan base->duplex = DUPLEX_HALF; 173783d8f5e9SMichael Chan } 173883d8f5e9SMichael Chan ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 1739c0c050c5SMichael Chan } else { 174000c04a92SMichael Chan base->autoneg = AUTONEG_DISABLE; 174129c262feSMichael Chan ethtool_speed = 174229c262feSMichael Chan bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 174300c04a92SMichael Chan base->duplex = DUPLEX_HALF; 174429c262feSMichael Chan if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 174500c04a92SMichael Chan base->duplex = DUPLEX_FULL; 1746c0c050c5SMichael Chan } 174700c04a92SMichael Chan base->speed = ethtool_speed; 1748c0c050c5SMichael Chan 174900c04a92SMichael Chan base->port = PORT_NONE; 1750c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 175100c04a92SMichael Chan base->port = PORT_TP; 175200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 175300c04a92SMichael Chan TP); 175400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 175500c04a92SMichael Chan TP); 1756c0c050c5SMichael Chan } else { 175700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 175800c04a92SMichael Chan FIBRE); 175900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176000c04a92SMichael Chan FIBRE); 1761c0c050c5SMichael Chan 1762c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 176300c04a92SMichael Chan base->port = PORT_DA; 1764c0c050c5SMichael Chan else if (link_info->media_type == 1765c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 176600c04a92SMichael Chan base->port = PORT_FIBRE; 1767c0c050c5SMichael Chan } 176800c04a92SMichael Chan base->phy_address = link_info->phy_addr; 1769e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1770c0c050c5SMichael Chan 1771c0c050c5SMichael Chan return 0; 1772c0c050c5SMichael Chan } 1773c0c050c5SMichael Chan 1774f00530bfSEdwin Peer static int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 1775c0c050c5SMichael Chan { 17769d9cee08SMichael Chan struct bnxt *bp = netdev_priv(dev); 17779d9cee08SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 1778532262baSEdwin Peer u16 support_pam4_spds = link_info->support_pam4_speeds; 17799d9cee08SMichael Chan u16 support_spds = link_info->support_speeds; 1780532262baSEdwin Peer u8 sig_mode = BNXT_SIG_MODE_NRZ; 1781f00530bfSEdwin Peer u16 fw_speed = 0; 17829d9cee08SMichael Chan 1783c0c050c5SMichael Chan switch (ethtool_speed) { 1784c0c050c5SMichael Chan case SPEED_100: 17859d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 1786f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17879d9cee08SMichael Chan break; 1788c0c050c5SMichael Chan case SPEED_1000: 17899d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 1790f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 17919d9cee08SMichael Chan break; 1792c0c050c5SMichael Chan case SPEED_2500: 17939d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 1794f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 17959d9cee08SMichael Chan break; 1796c0c050c5SMichael Chan case SPEED_10000: 17979d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 1798f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 17999d9cee08SMichael Chan break; 1800c0c050c5SMichael Chan case SPEED_20000: 18019d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 1802f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 18039d9cee08SMichael Chan break; 1804c0c050c5SMichael Chan case SPEED_25000: 18059d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 1806f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 18079d9cee08SMichael Chan break; 1808c0c050c5SMichael Chan case SPEED_40000: 18099d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 1810f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 18119d9cee08SMichael Chan break; 1812c0c050c5SMichael Chan case SPEED_50000: 1813532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 1814f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 1815532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 1816532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 1817532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1818532262baSEdwin Peer } 18199d9cee08SMichael Chan break; 182038a21b34SDeepak Khungar case SPEED_100000: 1821532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 1822f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 1823532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 1824532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 1825532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1826532262baSEdwin Peer } 1827532262baSEdwin Peer break; 1828532262baSEdwin Peer case SPEED_200000: 1829532262baSEdwin Peer if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 1830532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 1831532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1832532262baSEdwin Peer } 1833c0c050c5SMichael Chan break; 1834c0c050c5SMichael Chan } 1835f00530bfSEdwin Peer 1836f00530bfSEdwin Peer if (!fw_speed) { 1837f00530bfSEdwin Peer netdev_err(dev, "unsupported speed!\n"); 1838f00530bfSEdwin Peer return -EINVAL; 1839f00530bfSEdwin Peer } 1840f00530bfSEdwin Peer 1841745b5c65SEdwin Peer if (link_info->req_link_speed == fw_speed && 1842745b5c65SEdwin Peer link_info->req_signal_mode == sig_mode && 1843745b5c65SEdwin Peer link_info->autoneg == 0) 1844745b5c65SEdwin Peer return -EALREADY; 1845745b5c65SEdwin Peer 1846f00530bfSEdwin Peer link_info->req_link_speed = fw_speed; 1847532262baSEdwin Peer link_info->req_signal_mode = sig_mode; 1848f00530bfSEdwin Peer link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 1849f00530bfSEdwin Peer link_info->autoneg = 0; 1850f00530bfSEdwin Peer link_info->advertising = 0; 1851532262baSEdwin Peer link_info->advertising_pam4 = 0; 1852f00530bfSEdwin Peer 1853f00530bfSEdwin Peer return 0; 1854c0c050c5SMichael Chan } 1855c0c050c5SMichael Chan 1856939f7f0cSMichael Chan u16 bnxt_get_fw_auto_link_speeds(u32 advertising) 1857c0c050c5SMichael Chan { 1858c0c050c5SMichael Chan u16 fw_speed_mask = 0; 1859c0c050c5SMichael Chan 1860c0c050c5SMichael Chan /* only support autoneg at speed 100, 1000, and 10000 */ 1861c0c050c5SMichael Chan if (advertising & (ADVERTISED_100baseT_Full | 1862c0c050c5SMichael Chan ADVERTISED_100baseT_Half)) { 1863c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 1864c0c050c5SMichael Chan } 1865c0c050c5SMichael Chan if (advertising & (ADVERTISED_1000baseT_Full | 1866c0c050c5SMichael Chan ADVERTISED_1000baseT_Half)) { 1867c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 1868c0c050c5SMichael Chan } 1869c0c050c5SMichael Chan if (advertising & ADVERTISED_10000baseT_Full) 1870c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 1871c0c050c5SMichael Chan 18721c49c421SMichael Chan if (advertising & ADVERTISED_40000baseCR4_Full) 18731c49c421SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18741c49c421SMichael Chan 1875c0c050c5SMichael Chan return fw_speed_mask; 1876c0c050c5SMichael Chan } 1877c0c050c5SMichael Chan 187800c04a92SMichael Chan static int bnxt_set_link_ksettings(struct net_device *dev, 187900c04a92SMichael Chan const struct ethtool_link_ksettings *lk_ksettings) 1880c0c050c5SMichael Chan { 1881c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1882c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 188300c04a92SMichael Chan const struct ethtool_link_settings *base = &lk_ksettings->base; 1884c0c050c5SMichael Chan bool set_pause = false; 188568515a18SMichael Chan u32 speed; 188600c04a92SMichael Chan int rc = 0; 1887c0c050c5SMichael Chan 1888c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 188900c04a92SMichael Chan return -EOPNOTSUPP; 1890c0c050c5SMichael Chan 1891e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 189200c04a92SMichael Chan if (base->autoneg == AUTONEG_ENABLE) { 1893532262baSEdwin Peer link_info->advertising = 0; 1894532262baSEdwin Peer link_info->advertising_pam4 = 0; 1895532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 189600c04a92SMichael Chan advertising); 1897532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 1898532262baSEdwin Peer lk_ksettings, advertising); 1899c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_SPEED; 1900532262baSEdwin Peer if (!link_info->advertising && !link_info->advertising_pam4) { 190193ed8117SMichael Chan link_info->advertising = link_info->support_auto_speeds; 1902532262baSEdwin Peer link_info->advertising_pam4 = 1903532262baSEdwin Peer link_info->support_pam4_auto_speeds; 1904532262baSEdwin Peer } 1905c0c050c5SMichael Chan /* any change to autoneg will cause link change, therefore the 1906c0c050c5SMichael Chan * driver should put back the original pause setting in autoneg 1907c0c050c5SMichael Chan */ 19089a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 1909c0c050c5SMichael Chan set_pause = true; 1910c0c050c5SMichael Chan } else { 191103efbec0SMichael Chan u8 phy_type = link_info->phy_type; 19129d9cee08SMichael Chan 191303efbec0SMichael Chan if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 191403efbec0SMichael Chan phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 191503efbec0SMichael Chan link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 191603efbec0SMichael Chan netdev_err(dev, "10GBase-T devices must autoneg\n"); 191703efbec0SMichael Chan rc = -EINVAL; 191803efbec0SMichael Chan goto set_setting_exit; 191903efbec0SMichael Chan } 192000c04a92SMichael Chan if (base->duplex == DUPLEX_HALF) { 1921c0c050c5SMichael Chan netdev_err(dev, "HALF DUPLEX is not supported!\n"); 1922c0c050c5SMichael Chan rc = -EINVAL; 1923c0c050c5SMichael Chan goto set_setting_exit; 1924c0c050c5SMichael Chan } 192500c04a92SMichael Chan speed = base->speed; 1926f00530bfSEdwin Peer rc = bnxt_force_link_speed(dev, speed); 1927745b5c65SEdwin Peer if (rc) { 1928745b5c65SEdwin Peer if (rc == -EALREADY) 1929745b5c65SEdwin Peer rc = 0; 19309d9cee08SMichael Chan goto set_setting_exit; 19319d9cee08SMichael Chan } 1932745b5c65SEdwin Peer } 1933c0c050c5SMichael Chan 1934c0c050c5SMichael Chan if (netif_running(dev)) 1935939f7f0cSMichael Chan rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 1936c0c050c5SMichael Chan 1937c0c050c5SMichael Chan set_setting_exit: 1938e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1939c0c050c5SMichael Chan return rc; 1940c0c050c5SMichael Chan } 1941c0c050c5SMichael Chan 19428b277589SMichael Chan static int bnxt_get_fecparam(struct net_device *dev, 19438b277589SMichael Chan struct ethtool_fecparam *fec) 19448b277589SMichael Chan { 19458b277589SMichael Chan struct bnxt *bp = netdev_priv(dev); 19468b277589SMichael Chan struct bnxt_link_info *link_info; 19478b277589SMichael Chan u8 active_fec; 19488b277589SMichael Chan u16 fec_cfg; 19498b277589SMichael Chan 19508b277589SMichael Chan link_info = &bp->link_info; 19518b277589SMichael Chan fec_cfg = link_info->fec_cfg; 19528b277589SMichael Chan active_fec = link_info->active_fec_sig_mode & 19538b277589SMichael Chan PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19548b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 19558b277589SMichael Chan fec->fec = ETHTOOL_FEC_NONE; 19568b277589SMichael Chan fec->active_fec = ETHTOOL_FEC_NONE; 19578b277589SMichael Chan return 0; 19588b277589SMichael Chan } 19598b277589SMichael Chan if (fec_cfg & BNXT_FEC_AUTONEG) 19608b277589SMichael Chan fec->fec |= ETHTOOL_FEC_AUTO; 19618b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19628b277589SMichael Chan fec->fec |= ETHTOOL_FEC_BASER; 19638b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 19648b277589SMichael Chan fec->fec |= ETHTOOL_FEC_RS; 19658b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 19668b277589SMichael Chan fec->fec |= ETHTOOL_FEC_LLRS; 19678b277589SMichael Chan 19688b277589SMichael Chan switch (active_fec) { 19698b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19708b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_BASER; 19718b277589SMichael Chan break; 19728b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19738b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19748b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19758b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_RS; 19768b277589SMichael Chan break; 19778b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19788b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19798b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_LLRS; 19808b277589SMichael Chan break; 198184d3c83eSSomnath Kotur case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 198284d3c83eSSomnath Kotur fec->active_fec |= ETHTOOL_FEC_OFF; 198384d3c83eSSomnath Kotur break; 19848b277589SMichael Chan } 19858b277589SMichael Chan return 0; 19868b277589SMichael Chan } 19878b277589SMichael Chan 1988c9ca5c3aSJakub Kicinski static void bnxt_get_fec_stats(struct net_device *dev, 1989c9ca5c3aSJakub Kicinski struct ethtool_fec_stats *fec_stats) 1990c9ca5c3aSJakub Kicinski { 1991c9ca5c3aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 1992c9ca5c3aSJakub Kicinski u64 *rx; 1993c9ca5c3aSJakub Kicinski 1994c9ca5c3aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 1995c9ca5c3aSJakub Kicinski return; 1996c9ca5c3aSJakub Kicinski 1997c9ca5c3aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 1998c9ca5c3aSJakub Kicinski fec_stats->corrected_bits.total = 1999c9ca5c3aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 2000c9ca5c3aSJakub Kicinski } 2001c9ca5c3aSJakub Kicinski 2002ccd6a9dcSMichael Chan static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 2003ccd6a9dcSMichael Chan u32 fec) 2004ccd6a9dcSMichael Chan { 2005ccd6a9dcSMichael Chan u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 2006ccd6a9dcSMichael Chan 2007ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_BASER) 2008ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 2009ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_RS) 2010ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_RS_ON(link_info); 2011ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_LLRS) 2012ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_LLRS_ON; 2013ccd6a9dcSMichael Chan return fw_fec; 2014ccd6a9dcSMichael Chan } 2015ccd6a9dcSMichael Chan 2016ccd6a9dcSMichael Chan static int bnxt_set_fecparam(struct net_device *dev, 2017ccd6a9dcSMichael Chan struct ethtool_fecparam *fecparam) 2018ccd6a9dcSMichael Chan { 2019bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 2020ccd6a9dcSMichael Chan struct bnxt *bp = netdev_priv(dev); 2021ccd6a9dcSMichael Chan struct bnxt_link_info *link_info; 2022ccd6a9dcSMichael Chan u32 new_cfg, fec = fecparam->fec; 2023ccd6a9dcSMichael Chan u16 fec_cfg; 2024ccd6a9dcSMichael Chan int rc; 2025ccd6a9dcSMichael Chan 2026ccd6a9dcSMichael Chan link_info = &bp->link_info; 2027ccd6a9dcSMichael Chan fec_cfg = link_info->fec_cfg; 2028ccd6a9dcSMichael Chan if (fec_cfg & BNXT_FEC_NONE) 2029ccd6a9dcSMichael Chan return -EOPNOTSUPP; 2030ccd6a9dcSMichael Chan 2031ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_OFF) { 2032ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 2033ccd6a9dcSMichael Chan BNXT_FEC_ALL_OFF(link_info); 2034ccd6a9dcSMichael Chan goto apply_fec; 2035ccd6a9dcSMichael Chan } 2036ccd6a9dcSMichael Chan if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 2037ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 2038ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 2039ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 2040ccd6a9dcSMichael Chan return -EINVAL; 2041ccd6a9dcSMichael Chan 2042ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_AUTO) { 2043ccd6a9dcSMichael Chan if (!link_info->autoneg) 2044ccd6a9dcSMichael Chan return -EINVAL; 2045ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 2046ccd6a9dcSMichael Chan } else { 2047ccd6a9dcSMichael Chan new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 2048ccd6a9dcSMichael Chan } 2049ccd6a9dcSMichael Chan 2050ccd6a9dcSMichael Chan apply_fec: 2051bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 2052bbf33d1dSEdwin Peer if (rc) 2053bbf33d1dSEdwin Peer return rc; 2054bbf33d1dSEdwin Peer req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 2055bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2056ccd6a9dcSMichael Chan /* update current settings */ 2057ccd6a9dcSMichael Chan if (!rc) { 2058ccd6a9dcSMichael Chan mutex_lock(&bp->link_lock); 2059ccd6a9dcSMichael Chan bnxt_update_link(bp, false); 2060ccd6a9dcSMichael Chan mutex_unlock(&bp->link_lock); 2061ccd6a9dcSMichael Chan } 2062ccd6a9dcSMichael Chan return rc; 2063ccd6a9dcSMichael Chan } 2064ccd6a9dcSMichael Chan 2065c0c050c5SMichael Chan static void bnxt_get_pauseparam(struct net_device *dev, 2066c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2067c0c050c5SMichael Chan { 2068c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2069c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2070c0c050c5SMichael Chan 2071c0c050c5SMichael Chan if (BNXT_VF(bp)) 2072c0c050c5SMichael Chan return; 2073b763499eSMichael Chan epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20743c02d1bbSMichael Chan epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20753c02d1bbSMichael Chan epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 2076c0c050c5SMichael Chan } 2077c0c050c5SMichael Chan 2078423cffcfSJakub Kicinski static void bnxt_get_pause_stats(struct net_device *dev, 2079423cffcfSJakub Kicinski struct ethtool_pause_stats *epstat) 2080423cffcfSJakub Kicinski { 2081423cffcfSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2082423cffcfSJakub Kicinski u64 *rx, *tx; 2083423cffcfSJakub Kicinski 2084423cffcfSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 2085423cffcfSJakub Kicinski return; 2086423cffcfSJakub Kicinski 2087423cffcfSJakub Kicinski rx = bp->port_stats.sw_stats; 2088423cffcfSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 2089423cffcfSJakub Kicinski 2090423cffcfSJakub Kicinski epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 2091423cffcfSJakub Kicinski epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 2092423cffcfSJakub Kicinski } 2093423cffcfSJakub Kicinski 2094c0c050c5SMichael Chan static int bnxt_set_pauseparam(struct net_device *dev, 2095c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2096c0c050c5SMichael Chan { 2097c0c050c5SMichael Chan int rc = 0; 2098c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2099c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2100c0c050c5SMichael Chan 21019a3bc77eSMichael Chan if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 210275362a3fSMichael Chan return -EOPNOTSUPP; 2103c0c050c5SMichael Chan 2104a5390690SMichael Chan mutex_lock(&bp->link_lock); 2105c0c050c5SMichael Chan if (epause->autoneg) { 2106a5390690SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 2107a5390690SMichael Chan rc = -EINVAL; 2108a5390690SMichael Chan goto pause_exit; 2109a5390690SMichael Chan } 2110b763499eSMichael Chan 2111c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 2112*7c492a25SMichael Chan link_info->req_flow_ctrl = 0; 2113c0c050c5SMichael Chan } else { 2114c0c050c5SMichael Chan /* when transition from auto pause to force pause, 2115c0c050c5SMichael Chan * force a link change 2116c0c050c5SMichael Chan */ 2117c0c050c5SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 2118c0c050c5SMichael Chan link_info->force_link_chng = true; 2119c0c050c5SMichael Chan link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 2120c9ee9516SMichael Chan link_info->req_flow_ctrl = 0; 2121c0c050c5SMichael Chan } 2122c0c050c5SMichael Chan if (epause->rx_pause) 2123c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 2124c0c050c5SMichael Chan 2125c0c050c5SMichael Chan if (epause->tx_pause) 2126c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 2127c0c050c5SMichael Chan 2128a5390690SMichael Chan if (netif_running(dev)) 2129c0c050c5SMichael Chan rc = bnxt_hwrm_set_pause(bp); 2130a5390690SMichael Chan 2131a5390690SMichael Chan pause_exit: 2132163e9ef6SVasundhara Volam mutex_unlock(&bp->link_lock); 2133c0c050c5SMichael Chan return rc; 2134c0c050c5SMichael Chan } 2135c0c050c5SMichael Chan 2136c0c050c5SMichael Chan static u32 bnxt_get_link(struct net_device *dev) 2137c0c050c5SMichael Chan { 2138c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2139c0c050c5SMichael Chan 2140c0c050c5SMichael Chan /* TODO: handle MF, VF, driver close case */ 21410f5a4841SEdwin Peer return BNXT_LINK_IS_UP(bp); 2142c0c050c5SMichael Chan } 2143c0c050c5SMichael Chan 21444933f675SVasundhara Volam int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 21454933f675SVasundhara Volam struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 21464933f675SVasundhara Volam { 2147bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_output *resp; 2148bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_input *req; 21494933f675SVasundhara Volam int rc; 21504933f675SVasundhara Volam 21510ae0a779SVasundhara Volam if (BNXT_VF(bp)) 21520ae0a779SVasundhara Volam return -EOPNOTSUPP; 21530ae0a779SVasundhara Volam 2154bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 2155bbf33d1dSEdwin Peer if (rc) 2156bbf33d1dSEdwin Peer return rc; 2157bbf33d1dSEdwin Peer 2158bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 2159bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 21604933f675SVasundhara Volam if (!rc) 21614933f675SVasundhara Volam memcpy(nvm_dev_info, resp, sizeof(*resp)); 2162bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 21634933f675SVasundhara Volam return rc; 21644933f675SVasundhara Volam } 21654933f675SVasundhara Volam 2166b3b0ddd0SMichael Chan static void bnxt_print_admin_err(struct bnxt *bp) 2167b3b0ddd0SMichael Chan { 2168b3b0ddd0SMichael Chan netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 2169b3b0ddd0SMichael Chan } 2170b3b0ddd0SMichael Chan 21715ac67d8bSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21725ac67d8bSRob Swindell u16 ext, u16 *index, u32 *item_length, 21735ac67d8bSRob Swindell u32 *data_length); 21745ac67d8bSRob Swindell 2175bbf33d1dSEdwin Peer static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 217693ff3435SPavan Chebbi u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 217793ff3435SPavan Chebbi u32 dir_item_len, const u8 *data, 2178c0c050c5SMichael Chan size_t data_len) 2179c0c050c5SMichael Chan { 2180c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2181bbf33d1dSEdwin Peer struct hwrm_nvm_write_input *req; 2182c0c050c5SMichael Chan int rc; 2183c0c050c5SMichael Chan 2184bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 2185bbf33d1dSEdwin Peer if (rc) 2186bbf33d1dSEdwin Peer return rc; 2187c0c050c5SMichael Chan 218893ff3435SPavan Chebbi if (data_len && data) { 2189bbf33d1dSEdwin Peer dma_addr_t dma_handle; 2190bbf33d1dSEdwin Peer u8 *kmem; 2191c0c050c5SMichael Chan 2192bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 2193bbf33d1dSEdwin Peer if (!kmem) { 2194bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2195c0c050c5SMichael Chan return -ENOMEM; 219693ff3435SPavan Chebbi } 2197c0c050c5SMichael Chan 2198bbf33d1dSEdwin Peer req->dir_data_length = cpu_to_le32(data_len); 2199bbf33d1dSEdwin Peer 2200bbf33d1dSEdwin Peer memcpy(kmem, data, data_len); 2201bbf33d1dSEdwin Peer req->host_src_addr = cpu_to_le64(dma_handle); 2202bbf33d1dSEdwin Peer } 2203bbf33d1dSEdwin Peer 2204bce9a0b7SEdwin Peer hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 2205bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(dir_type); 2206bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(dir_ordinal); 2207bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(dir_ext); 2208bbf33d1dSEdwin Peer req->dir_attr = cpu_to_le16(dir_attr); 2209bbf33d1dSEdwin Peer req->dir_item_length = cpu_to_le32(dir_item_len); 2210bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2211c0c050c5SMichael Chan 2212d4f1420dSMichael Chan if (rc == -EACCES) 2213b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2214c0c050c5SMichael Chan return rc; 2215c0c050c5SMichael Chan } 2216c0c050c5SMichael Chan 22178f6c5e4dSEdwin Peer int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 221895fec034SEdwin Peer u8 self_reset, u8 flags) 2219d2d6318cSRob Swindell { 22207c675421SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 2221bbf33d1dSEdwin Peer struct hwrm_fw_reset_input *req; 22227c675421SVasundhara Volam int rc; 2223d2d6318cSRob Swindell 2224892a662fSEdwin Peer if (!bnxt_hwrm_reset_permitted(bp)) { 2225892a662fSEdwin Peer netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 2226892a662fSEdwin Peer return -EPERM; 2227892a662fSEdwin Peer } 2228892a662fSEdwin Peer 2229bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 2230bbf33d1dSEdwin Peer if (rc) 2231bbf33d1dSEdwin Peer return rc; 2232d2d6318cSRob Swindell 2233bbf33d1dSEdwin Peer req->embedded_proc_type = proc_type; 2234bbf33d1dSEdwin Peer req->selfrst_status = self_reset; 2235bbf33d1dSEdwin Peer req->flags = flags; 223695fec034SEdwin Peer 22378cec0940SEdwin Peer if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 2238bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 22398cec0940SEdwin Peer } else { 2240bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 224195fec034SEdwin Peer if (rc == -EACCES) 224295fec034SEdwin Peer bnxt_print_admin_err(bp); 22438cec0940SEdwin Peer } 224495fec034SEdwin Peer return rc; 224595fec034SEdwin Peer } 224695fec034SEdwin Peer 224794f17e89SEdwin Peer static int bnxt_firmware_reset(struct net_device *dev, 224894f17e89SEdwin Peer enum bnxt_nvm_directory_type dir_type) 224995fec034SEdwin Peer { 225095fec034SEdwin Peer u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 225195fec034SEdwin Peer u8 proc_type, flags = 0; 225295fec034SEdwin Peer 2253d2d6318cSRob Swindell /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 2254d2d6318cSRob Swindell /* (e.g. when firmware isn't already running) */ 2255d2d6318cSRob Swindell switch (dir_type) { 2256d2d6318cSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 2257d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE: 2258d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE_2: 225995fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 2260d2d6318cSRob Swindell /* Self-reset ChiMP upon next PCIe reset: */ 226195fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2262d2d6318cSRob Swindell break; 2263d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_FW: 2264d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 226595fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 226608141e0bSRob Swindell /* Self-reset APE upon next PCIe reset: */ 226795fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2268d2d6318cSRob Swindell break; 2269d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_FW: 2270d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 227195fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 2272d2d6318cSRob Swindell break; 2273d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_FW: 2274d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 227595fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 2276d2d6318cSRob Swindell break; 2277d2d6318cSRob Swindell default: 2278d2d6318cSRob Swindell return -EINVAL; 2279d2d6318cSRob Swindell } 2280d2d6318cSRob Swindell 228195fec034SEdwin Peer return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 2282d2d6318cSRob Swindell } 2283d2d6318cSRob Swindell 228494f17e89SEdwin Peer static int bnxt_firmware_reset_chip(struct net_device *dev) 228594f17e89SEdwin Peer { 228694f17e89SEdwin Peer struct bnxt *bp = netdev_priv(dev); 228794f17e89SEdwin Peer u8 flags = 0; 228894f17e89SEdwin Peer 228994f17e89SEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 229094f17e89SEdwin Peer flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 229194f17e89SEdwin Peer 229294f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, 229394f17e89SEdwin Peer FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 229494f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 229594f17e89SEdwin Peer flags); 229694f17e89SEdwin Peer } 229794f17e89SEdwin Peer 229894f17e89SEdwin Peer static int bnxt_firmware_reset_ap(struct net_device *dev) 229994f17e89SEdwin Peer { 230094f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 230194f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 230294f17e89SEdwin Peer 0); 230394f17e89SEdwin Peer } 230494f17e89SEdwin Peer 2305c0c050c5SMichael Chan static int bnxt_flash_firmware(struct net_device *dev, 2306c0c050c5SMichael Chan u16 dir_type, 2307c0c050c5SMichael Chan const u8 *fw_data, 2308c0c050c5SMichael Chan size_t fw_size) 2309c0c050c5SMichael Chan { 2310c0c050c5SMichael Chan int rc = 0; 2311c0c050c5SMichael Chan u16 code_type; 2312c0c050c5SMichael Chan u32 stored_crc; 2313c0c050c5SMichael Chan u32 calculated_crc; 2314c0c050c5SMichael Chan struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 2315c0c050c5SMichael Chan 2316c0c050c5SMichael Chan switch (dir_type) { 2317c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2318c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2319c0c050c5SMichael Chan code_type = CODE_BOOT; 2320c0c050c5SMichael Chan break; 232193e0b4feSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 232293e0b4feSRob Swindell code_type = CODE_CHIMP_PATCH; 232393e0b4feSRob Swindell break; 23242731d70fSRob Swindell case BNX_DIR_TYPE_APE_FW: 23252731d70fSRob Swindell code_type = CODE_MCTP_PASSTHRU; 23262731d70fSRob Swindell break; 232793e0b4feSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 232893e0b4feSRob Swindell code_type = CODE_APE_PATCH; 232993e0b4feSRob Swindell break; 233093e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_FW: 233193e0b4feSRob Swindell code_type = CODE_KONG_FW; 233293e0b4feSRob Swindell break; 233393e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 233493e0b4feSRob Swindell code_type = CODE_KONG_PATCH; 233593e0b4feSRob Swindell break; 233693e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 233793e0b4feSRob Swindell code_type = CODE_BONO_FW; 233893e0b4feSRob Swindell break; 233993e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 234093e0b4feSRob Swindell code_type = CODE_BONO_PATCH; 234193e0b4feSRob Swindell break; 2342c0c050c5SMichael Chan default: 2343c0c050c5SMichael Chan netdev_err(dev, "Unsupported directory entry type: %u\n", 2344c0c050c5SMichael Chan dir_type); 2345c0c050c5SMichael Chan return -EINVAL; 2346c0c050c5SMichael Chan } 2347c0c050c5SMichael Chan if (fw_size < sizeof(struct bnxt_fw_header)) { 2348c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware file size: %u\n", 2349c0c050c5SMichael Chan (unsigned int)fw_size); 2350c0c050c5SMichael Chan return -EINVAL; 2351c0c050c5SMichael Chan } 2352c0c050c5SMichael Chan if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 2353c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware signature: %08X\n", 2354c0c050c5SMichael Chan le32_to_cpu(header->signature)); 2355c0c050c5SMichael Chan return -EINVAL; 2356c0c050c5SMichael Chan } 2357c0c050c5SMichael Chan if (header->code_type != code_type) { 2358c0c050c5SMichael Chan netdev_err(dev, "Expected firmware type: %d, read: %d\n", 2359c0c050c5SMichael Chan code_type, header->code_type); 2360c0c050c5SMichael Chan return -EINVAL; 2361c0c050c5SMichael Chan } 2362c0c050c5SMichael Chan if (header->device != DEVICE_CUMULUS_FAMILY) { 2363c0c050c5SMichael Chan netdev_err(dev, "Expected firmware device family %d, read: %d\n", 2364c0c050c5SMichael Chan DEVICE_CUMULUS_FAMILY, header->device); 2365c0c050c5SMichael Chan return -EINVAL; 2366c0c050c5SMichael Chan } 2367c0c050c5SMichael Chan /* Confirm the CRC32 checksum of the file: */ 2368c0c050c5SMichael Chan stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 2369c0c050c5SMichael Chan sizeof(stored_crc))); 2370c0c050c5SMichael Chan calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 2371c0c050c5SMichael Chan if (calculated_crc != stored_crc) { 2372c0c050c5SMichael Chan netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 2373c0c050c5SMichael Chan (unsigned long)stored_crc, 2374c0c050c5SMichael Chan (unsigned long)calculated_crc); 2375c0c050c5SMichael Chan return -EINVAL; 2376c0c050c5SMichael Chan } 2377c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2378bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 2379d2d6318cSRob Swindell if (rc == 0) /* Firmware update successful */ 2380d2d6318cSRob Swindell rc = bnxt_firmware_reset(dev, dir_type); 2381d2d6318cSRob Swindell 2382c0c050c5SMichael Chan return rc; 2383c0c050c5SMichael Chan } 2384c0c050c5SMichael Chan 23855ac67d8bSRob Swindell static int bnxt_flash_microcode(struct net_device *dev, 23865ac67d8bSRob Swindell u16 dir_type, 23875ac67d8bSRob Swindell const u8 *fw_data, 23885ac67d8bSRob Swindell size_t fw_size) 23895ac67d8bSRob Swindell { 23905ac67d8bSRob Swindell struct bnxt_ucode_trailer *trailer; 23915ac67d8bSRob Swindell u32 calculated_crc; 23925ac67d8bSRob Swindell u32 stored_crc; 23935ac67d8bSRob Swindell int rc = 0; 23945ac67d8bSRob Swindell 23955ac67d8bSRob Swindell if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 23965ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode file size: %u\n", 23975ac67d8bSRob Swindell (unsigned int)fw_size); 23985ac67d8bSRob Swindell return -EINVAL; 23995ac67d8bSRob Swindell } 24005ac67d8bSRob Swindell trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 24015ac67d8bSRob Swindell sizeof(*trailer))); 24025ac67d8bSRob Swindell if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 24035ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 24045ac67d8bSRob Swindell le32_to_cpu(trailer->sig)); 24055ac67d8bSRob Swindell return -EINVAL; 24065ac67d8bSRob Swindell } 24075ac67d8bSRob Swindell if (le16_to_cpu(trailer->dir_type) != dir_type) { 24085ac67d8bSRob Swindell netdev_err(dev, "Expected microcode type: %d, read: %d\n", 24095ac67d8bSRob Swindell dir_type, le16_to_cpu(trailer->dir_type)); 24105ac67d8bSRob Swindell return -EINVAL; 24115ac67d8bSRob Swindell } 24125ac67d8bSRob Swindell if (le16_to_cpu(trailer->trailer_length) < 24135ac67d8bSRob Swindell sizeof(struct bnxt_ucode_trailer)) { 24145ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer length: %d\n", 24155ac67d8bSRob Swindell le16_to_cpu(trailer->trailer_length)); 24165ac67d8bSRob Swindell return -EINVAL; 24175ac67d8bSRob Swindell } 24185ac67d8bSRob Swindell 24195ac67d8bSRob Swindell /* Confirm the CRC32 checksum of the file: */ 24205ac67d8bSRob Swindell stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 24215ac67d8bSRob Swindell sizeof(stored_crc))); 24225ac67d8bSRob Swindell calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 24235ac67d8bSRob Swindell if (calculated_crc != stored_crc) { 24245ac67d8bSRob Swindell netdev_err(dev, 24255ac67d8bSRob Swindell "CRC32 (%08lX) does not match calculated: %08lX\n", 24265ac67d8bSRob Swindell (unsigned long)stored_crc, 24275ac67d8bSRob Swindell (unsigned long)calculated_crc); 24285ac67d8bSRob Swindell return -EINVAL; 24295ac67d8bSRob Swindell } 24305ac67d8bSRob Swindell rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2431bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 24325ac67d8bSRob Swindell 24335ac67d8bSRob Swindell return rc; 24345ac67d8bSRob Swindell } 24355ac67d8bSRob Swindell 2436c0c050c5SMichael Chan static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 2437c0c050c5SMichael Chan { 2438c0c050c5SMichael Chan switch (dir_type) { 2439c0c050c5SMichael Chan case BNX_DIR_TYPE_CHIMP_PATCH: 2440c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2441c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2442c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_FW: 2443c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_PATCH: 2444c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_FW: 2445c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_PATCH: 244693e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 244793e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 2448c0c050c5SMichael Chan return true; 2449c0c050c5SMichael Chan } 2450c0c050c5SMichael Chan 2451c0c050c5SMichael Chan return false; 2452c0c050c5SMichael Chan } 2453c0c050c5SMichael Chan 24545ac67d8bSRob Swindell static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 2455c0c050c5SMichael Chan { 2456c0c050c5SMichael Chan switch (dir_type) { 2457c0c050c5SMichael Chan case BNX_DIR_TYPE_AVS: 2458c0c050c5SMichael Chan case BNX_DIR_TYPE_EXP_ROM_MBA: 2459c0c050c5SMichael Chan case BNX_DIR_TYPE_PCIE: 2460c0c050c5SMichael Chan case BNX_DIR_TYPE_TSCF_UCODE: 2461c0c050c5SMichael Chan case BNX_DIR_TYPE_EXT_PHY: 2462c0c050c5SMichael Chan case BNX_DIR_TYPE_CCM: 2463c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT: 2464c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 2465c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 2466c0c050c5SMichael Chan return true; 2467c0c050c5SMichael Chan } 2468c0c050c5SMichael Chan 2469c0c050c5SMichael Chan return false; 2470c0c050c5SMichael Chan } 2471c0c050c5SMichael Chan 2472c0c050c5SMichael Chan static bool bnxt_dir_type_is_executable(u16 dir_type) 2473c0c050c5SMichael Chan { 2474c0c050c5SMichael Chan return bnxt_dir_type_is_ape_bin_format(dir_type) || 24755ac67d8bSRob Swindell bnxt_dir_type_is_other_exec_format(dir_type); 2476c0c050c5SMichael Chan } 2477c0c050c5SMichael Chan 2478c0c050c5SMichael Chan static int bnxt_flash_firmware_from_file(struct net_device *dev, 2479c0c050c5SMichael Chan u16 dir_type, 2480c0c050c5SMichael Chan const char *filename) 2481c0c050c5SMichael Chan { 2482c0c050c5SMichael Chan const struct firmware *fw; 2483c0c050c5SMichael Chan int rc; 2484c0c050c5SMichael Chan 2485c0c050c5SMichael Chan rc = request_firmware(&fw, filename, &dev->dev); 2486c0c050c5SMichael Chan if (rc != 0) { 2487c0c050c5SMichael Chan netdev_err(dev, "Error %d requesting firmware file: %s\n", 2488c0c050c5SMichael Chan rc, filename); 2489c0c050c5SMichael Chan return rc; 2490c0c050c5SMichael Chan } 2491ba425800SJason Yan if (bnxt_dir_type_is_ape_bin_format(dir_type)) 2492c0c050c5SMichael Chan rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 2493ba425800SJason Yan else if (bnxt_dir_type_is_other_exec_format(dir_type)) 24945ac67d8bSRob Swindell rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 2495c0c050c5SMichael Chan else 2496c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2497bbf33d1dSEdwin Peer 0, 0, 0, fw->data, fw->size); 2498c0c050c5SMichael Chan release_firmware(fw); 2499c0c050c5SMichael Chan return rc; 2500c0c050c5SMichael Chan } 2501c0c050c5SMichael Chan 250202acd399SKalesh AP static int nvm_update_err_to_stderr(struct net_device *dev, u8 result) 250302acd399SKalesh AP { 250402acd399SKalesh AP switch (result) { 250502acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER: 250602acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER: 250702acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR: 250802acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR: 250902acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND: 251002acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED: 251102acd399SKalesh AP netdev_err(dev, "PKG install error : Data integrity on NVM\n"); 251202acd399SKalesh AP return -EINVAL; 251302acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE: 251402acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER: 251502acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE: 251602acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM: 251702acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH: 251802acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST: 251902acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER: 252002acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM: 252102acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM: 252202acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH: 252302acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE: 252402acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM: 252502acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM: 252602acd399SKalesh AP netdev_err(dev, "PKG install error : Invalid package\n"); 252702acd399SKalesh AP return -ENOPKG; 252802acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR: 252902acd399SKalesh AP netdev_err(dev, "PKG install error : Authentication error\n"); 253002acd399SKalesh AP return -EPERM; 253102acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV: 253202acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID: 253302acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR: 253402acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID: 253502acd399SKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM: 253602acd399SKalesh AP netdev_err(dev, "PKG install error : Invalid device\n"); 253702acd399SKalesh AP return -EOPNOTSUPP; 253802acd399SKalesh AP default: 253902acd399SKalesh AP netdev_err(dev, "PKG install error : Internal error\n"); 254002acd399SKalesh AP return -EIO; 254102acd399SKalesh AP } 254202acd399SKalesh AP } 254302acd399SKalesh AP 2544a86b313eSMichael Chan #define BNXT_PKG_DMA_SIZE 0x40000 2545a86b313eSMichael Chan #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 2546a86b313eSMichael Chan #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 2547a86b313eSMichael Chan 2548b44cfd4fSJacob Keller int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 2549d168f328SVasundhara Volam u32 install_type) 2550c0c050c5SMichael Chan { 2551bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_input *install; 2552bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_output *resp; 2553bbf33d1dSEdwin Peer struct hwrm_nvm_modify_input *modify; 2554a9094ba6SMichael Chan struct bnxt *bp = netdev_priv(dev); 25551432c3f6SPavan Chebbi bool defrag_attempted = false; 2556a9094ba6SMichael Chan dma_addr_t dma_handle; 2557a9094ba6SMichael Chan u8 *kmem = NULL; 2558a86b313eSMichael Chan u32 modify_len; 25595ac67d8bSRob Swindell u32 item_len; 25608e42aef0SKalesh AP u8 cmd_err; 25615ac67d8bSRob Swindell u16 index; 2562bbf33d1dSEdwin Peer int rc; 25635ac67d8bSRob Swindell 25645ac67d8bSRob Swindell bnxt_hwrm_fw_set_time(bp); 25655ac67d8bSRob Swindell 2566bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 2567bbf33d1dSEdwin Peer if (rc) 2568bbf33d1dSEdwin Peer return rc; 2569a9094ba6SMichael Chan 2570a86b313eSMichael Chan /* Try allocating a large DMA buffer first. Older fw will 2571a86b313eSMichael Chan * cause excessive NVRAM erases when using small blocks. 2572a86b313eSMichael Chan */ 2573a86b313eSMichael Chan modify_len = roundup_pow_of_two(fw->size); 2574a86b313eSMichael Chan modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 2575a86b313eSMichael Chan while (1) { 2576bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 2577a86b313eSMichael Chan if (!kmem && modify_len > PAGE_SIZE) 2578a86b313eSMichael Chan modify_len /= 2; 2579a86b313eSMichael Chan else 2580a86b313eSMichael Chan break; 2581a86b313eSMichael Chan } 2582bbf33d1dSEdwin Peer if (!kmem) { 2583bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2584a9094ba6SMichael Chan return -ENOMEM; 2585bbf33d1dSEdwin Peer } 2586a9094ba6SMichael Chan 2587bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 2588bbf33d1dSEdwin Peer if (rc) { 2589bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2590bbf33d1dSEdwin Peer return rc; 2591bbf33d1dSEdwin Peer } 2592a9094ba6SMichael Chan 2593bce9a0b7SEdwin Peer hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 2594bce9a0b7SEdwin Peer hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 2595bbf33d1dSEdwin Peer 2596bbf33d1dSEdwin Peer hwrm_req_hold(bp, modify); 2597bbf33d1dSEdwin Peer modify->host_src_addr = cpu_to_le64(dma_handle); 2598bbf33d1dSEdwin Peer 2599bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, install); 2600a9094ba6SMichael Chan if ((install_type & 0xffff) == 0) 2601a9094ba6SMichael Chan install_type >>= 16; 2602bbf33d1dSEdwin Peer install->install_type = cpu_to_le32(install_type); 2603a9094ba6SMichael Chan 26042e5fb428SPavan Chebbi do { 2605a86b313eSMichael Chan u32 copied = 0, len = modify_len; 2606a86b313eSMichael Chan 260795ec1f47SVasundhara Volam rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 26082e5fb428SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 26092e5fb428SPavan Chebbi BNX_DIR_EXT_NONE, 261095ec1f47SVasundhara Volam &index, &item_len, NULL); 261195ec1f47SVasundhara Volam if (rc) { 26125ac67d8bSRob Swindell netdev_err(dev, "PKG update area not created in nvram\n"); 26132e5fb428SPavan Chebbi break; 26145ac67d8bSRob Swindell } 26155ac67d8bSRob Swindell if (fw->size > item_len) { 26169a005c38SJonathan Lemon netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", 26175ac67d8bSRob Swindell (unsigned long)fw->size); 26185ac67d8bSRob Swindell rc = -EFBIG; 26192e5fb428SPavan Chebbi break; 26202e5fb428SPavan Chebbi } 26212e5fb428SPavan Chebbi 2622bbf33d1dSEdwin Peer modify->dir_idx = cpu_to_le16(index); 26235ac67d8bSRob Swindell 2624a86b313eSMichael Chan if (fw->size > modify_len) 2625bbf33d1dSEdwin Peer modify->flags = BNXT_NVM_MORE_FLAG; 2626a86b313eSMichael Chan while (copied < fw->size) { 2627a86b313eSMichael Chan u32 balance = fw->size - copied; 2628a86b313eSMichael Chan 2629a86b313eSMichael Chan if (balance <= modify_len) { 2630a86b313eSMichael Chan len = balance; 2631a86b313eSMichael Chan if (copied) 2632bbf33d1dSEdwin Peer modify->flags |= BNXT_NVM_LAST_FLAG; 2633a86b313eSMichael Chan } 2634a86b313eSMichael Chan memcpy(kmem, fw->data + copied, len); 2635bbf33d1dSEdwin Peer modify->len = cpu_to_le32(len); 2636bbf33d1dSEdwin Peer modify->offset = cpu_to_le32(copied); 2637bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, modify); 263822630e28SEdwin Peer if (rc) 2639a86b313eSMichael Chan goto pkg_abort; 2640a86b313eSMichael Chan copied += len; 2641a86b313eSMichael Chan } 2642bbf33d1dSEdwin Peer 2643bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 26448e42aef0SKalesh AP if (!rc) 26458e42aef0SKalesh AP break; 2646cb4d1d62SKshitij Soni 26471432c3f6SPavan Chebbi if (defrag_attempted) { 26481432c3f6SPavan Chebbi /* We have tried to defragment already in the previous 26491432c3f6SPavan Chebbi * iteration. Return with the result for INSTALL_UPDATE 26501432c3f6SPavan Chebbi */ 26511432c3f6SPavan Chebbi break; 26521432c3f6SPavan Chebbi } 26531432c3f6SPavan Chebbi 26548e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 26558e42aef0SKalesh AP 26568e42aef0SKalesh AP switch (cmd_err) { 265754ff1e3eSKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: 265854ff1e3eSKalesh AP netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure Anti-rollback detected\n"); 265954ff1e3eSKalesh AP rc = -EALREADY; 266054ff1e3eSKalesh AP break; 26618e42aef0SKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: 2662bbf33d1dSEdwin Peer install->flags = 26632e5fb428SPavan Chebbi cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 26642e5fb428SPavan Chebbi 2665bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 26668e42aef0SKalesh AP if (!rc) 26678e42aef0SKalesh AP break; 26681432c3f6SPavan Chebbi 26698e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 26708e42aef0SKalesh AP 26718e42aef0SKalesh AP if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 26721432c3f6SPavan Chebbi /* FW has cleared NVM area, driver will create 26731432c3f6SPavan Chebbi * UPDATE directory and try the flash again 26741432c3f6SPavan Chebbi */ 26751432c3f6SPavan Chebbi defrag_attempted = true; 2676bbf33d1dSEdwin Peer install->flags = 0; 2677bbf33d1dSEdwin Peer rc = bnxt_flash_nvram(bp->dev, 26781432c3f6SPavan Chebbi BNX_DIR_TYPE_UPDATE, 26791432c3f6SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 2680bbf33d1dSEdwin Peer 0, 0, item_len, NULL, 0); 26818e42aef0SKalesh AP if (!rc) 26828e42aef0SKalesh AP break; 26831432c3f6SPavan Chebbi } 26848e42aef0SKalesh AP fallthrough; 26858e42aef0SKalesh AP default: 26868e42aef0SKalesh AP netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x cmd_err :%x\n", 26878e42aef0SKalesh AP rc, cmd_err); 2688dd2ebf34SVasundhara Volam } 26891432c3f6SPavan Chebbi } while (defrag_attempted && !rc); 26905ac67d8bSRob Swindell 2691a86b313eSMichael Chan pkg_abort: 2692bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2693bbf33d1dSEdwin Peer hwrm_req_drop(bp, install); 2694bbf33d1dSEdwin Peer 2695bbf33d1dSEdwin Peer if (resp->result) { 26965ac67d8bSRob Swindell netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 2697bbf33d1dSEdwin Peer (s8)resp->result, (int)resp->problem_item); 269802acd399SKalesh AP rc = nvm_update_err_to_stderr(dev, resp->result); 26995ac67d8bSRob Swindell } 270022630e28SEdwin Peer if (rc == -EACCES) 2701b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2702cb4d1d62SKshitij Soni return rc; 2703c0c050c5SMichael Chan } 2704c0c050c5SMichael Chan 2705b44cfd4fSJacob Keller static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 2706b44cfd4fSJacob Keller u32 install_type) 2707b44cfd4fSJacob Keller { 2708b44cfd4fSJacob Keller const struct firmware *fw; 2709b44cfd4fSJacob Keller int rc; 2710b44cfd4fSJacob Keller 2711b44cfd4fSJacob Keller rc = request_firmware(&fw, filename, &dev->dev); 2712b44cfd4fSJacob Keller if (rc != 0) { 2713b44cfd4fSJacob Keller netdev_err(dev, "PKG error %d requesting file: %s\n", 2714b44cfd4fSJacob Keller rc, filename); 2715b44cfd4fSJacob Keller return rc; 2716b44cfd4fSJacob Keller } 2717b44cfd4fSJacob Keller 2718b44cfd4fSJacob Keller rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type); 2719b44cfd4fSJacob Keller 2720b44cfd4fSJacob Keller release_firmware(fw); 2721b44cfd4fSJacob Keller 2722b44cfd4fSJacob Keller return rc; 2723b44cfd4fSJacob Keller } 2724b44cfd4fSJacob Keller 2725c0c050c5SMichael Chan static int bnxt_flash_device(struct net_device *dev, 2726c0c050c5SMichael Chan struct ethtool_flash *flash) 2727c0c050c5SMichael Chan { 2728c0c050c5SMichael Chan if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 2729c0c050c5SMichael Chan netdev_err(dev, "flashdev not supported from a virtual function\n"); 2730c0c050c5SMichael Chan return -EINVAL; 2731c0c050c5SMichael Chan } 2732c0c050c5SMichael Chan 27335ac67d8bSRob Swindell if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 27345ac67d8bSRob Swindell flash->region > 0xffff) 27355ac67d8bSRob Swindell return bnxt_flash_package_from_file(dev, flash->data, 27365ac67d8bSRob Swindell flash->region); 2737c0c050c5SMichael Chan 2738c0c050c5SMichael Chan return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 2739c0c050c5SMichael Chan } 2740c0c050c5SMichael Chan 2741c0c050c5SMichael Chan static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 2742c0c050c5SMichael Chan { 2743bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_output *output; 2744bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_input *req; 2745c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2746c0c050c5SMichael Chan int rc; 2747c0c050c5SMichael Chan 2748bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 2749bbf33d1dSEdwin Peer if (rc) 2750bbf33d1dSEdwin Peer return rc; 2751c0c050c5SMichael Chan 2752bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2753bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2754c0c050c5SMichael Chan if (!rc) { 2755c0c050c5SMichael Chan *entries = le32_to_cpu(output->entries); 2756c0c050c5SMichael Chan *length = le32_to_cpu(output->entry_length); 2757c0c050c5SMichael Chan } 2758bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2759c0c050c5SMichael Chan return rc; 2760c0c050c5SMichael Chan } 2761c0c050c5SMichael Chan 2762c0c050c5SMichael Chan static int bnxt_get_eeprom_len(struct net_device *dev) 2763c0c050c5SMichael Chan { 27644cebbacaSMichael Chan struct bnxt *bp = netdev_priv(dev); 27654cebbacaSMichael Chan 27664cebbacaSMichael Chan if (BNXT_VF(bp)) 27674cebbacaSMichael Chan return 0; 27684cebbacaSMichael Chan 2769c0c050c5SMichael Chan /* The -1 return value allows the entire 32-bit range of offsets to be 2770c0c050c5SMichael Chan * passed via the ethtool command-line utility. 2771c0c050c5SMichael Chan */ 2772c0c050c5SMichael Chan return -1; 2773c0c050c5SMichael Chan } 2774c0c050c5SMichael Chan 2775c0c050c5SMichael Chan static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 2776c0c050c5SMichael Chan { 2777c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2778c0c050c5SMichael Chan int rc; 2779c0c050c5SMichael Chan u32 dir_entries; 2780c0c050c5SMichael Chan u32 entry_length; 2781c0c050c5SMichael Chan u8 *buf; 2782c0c050c5SMichael Chan size_t buflen; 2783c0c050c5SMichael Chan dma_addr_t dma_handle; 2784bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_entries_input *req; 2785c0c050c5SMichael Chan 2786c0c050c5SMichael Chan rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 2787c0c050c5SMichael Chan if (rc != 0) 2788c0c050c5SMichael Chan return rc; 2789c0c050c5SMichael Chan 2790dbbfa96aSVasundhara Volam if (!dir_entries || !entry_length) 2791dbbfa96aSVasundhara Volam return -EIO; 2792dbbfa96aSVasundhara Volam 2793c0c050c5SMichael Chan /* Insert 2 bytes of directory info (count and size of entries) */ 2794c0c050c5SMichael Chan if (len < 2) 2795c0c050c5SMichael Chan return -EINVAL; 2796c0c050c5SMichael Chan 2797c0c050c5SMichael Chan *data++ = dir_entries; 2798c0c050c5SMichael Chan *data++ = entry_length; 2799c0c050c5SMichael Chan len -= 2; 2800c0c050c5SMichael Chan memset(data, 0xff, len); 2801c0c050c5SMichael Chan 2802bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 2803bbf33d1dSEdwin Peer if (rc) 2804bbf33d1dSEdwin Peer return rc; 2805bbf33d1dSEdwin Peer 2806c0c050c5SMichael Chan buflen = dir_entries * entry_length; 2807bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 2808c0c050c5SMichael Chan if (!buf) { 2809bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2810c0c050c5SMichael Chan return -ENOMEM; 2811c0c050c5SMichael Chan } 2812bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2813bbf33d1dSEdwin Peer 2814bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2815bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2816c0c050c5SMichael Chan if (rc == 0) 2817c0c050c5SMichael Chan memcpy(data, buf, len > buflen ? buflen : len); 2818bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2819c0c050c5SMichael Chan return rc; 2820c0c050c5SMichael Chan } 2821c0c050c5SMichael Chan 2822c0c050c5SMichael Chan static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 2823c0c050c5SMichael Chan u32 length, u8 *data) 2824c0c050c5SMichael Chan { 2825c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2826c0c050c5SMichael Chan int rc; 2827c0c050c5SMichael Chan u8 *buf; 2828c0c050c5SMichael Chan dma_addr_t dma_handle; 2829bbf33d1dSEdwin Peer struct hwrm_nvm_read_input *req; 2830c0c050c5SMichael Chan 2831e0ad8fc5SMichael Chan if (!length) 2832e0ad8fc5SMichael Chan return -EINVAL; 2833e0ad8fc5SMichael Chan 2834bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 2835bbf33d1dSEdwin Peer if (rc) 2836bbf33d1dSEdwin Peer return rc; 2837bbf33d1dSEdwin Peer 2838bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 2839c0c050c5SMichael Chan if (!buf) { 2840bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2841c0c050c5SMichael Chan return -ENOMEM; 2842c0c050c5SMichael Chan } 2843c0c050c5SMichael Chan 2844bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2845bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2846bbf33d1dSEdwin Peer req->offset = cpu_to_le32(offset); 2847bbf33d1dSEdwin Peer req->len = cpu_to_le32(length); 2848bbf33d1dSEdwin Peer 2849bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2850bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2851c0c050c5SMichael Chan if (rc == 0) 2852c0c050c5SMichael Chan memcpy(data, buf, length); 2853bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2854c0c050c5SMichael Chan return rc; 2855c0c050c5SMichael Chan } 2856c0c050c5SMichael Chan 28573ebf6f0aSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 28583ebf6f0aSRob Swindell u16 ext, u16 *index, u32 *item_length, 28593ebf6f0aSRob Swindell u32 *data_length) 28603ebf6f0aSRob Swindell { 2861bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_output *output; 2862bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_input *req; 28633ebf6f0aSRob Swindell struct bnxt *bp = netdev_priv(dev); 28643ebf6f0aSRob Swindell int rc; 28653ebf6f0aSRob Swindell 2866bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 2867bbf33d1dSEdwin Peer if (rc) 2868bbf33d1dSEdwin Peer return rc; 2869bbf33d1dSEdwin Peer 2870bbf33d1dSEdwin Peer req->enables = 0; 2871bbf33d1dSEdwin Peer req->dir_idx = 0; 2872bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(type); 2873bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(ordinal); 2874bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(ext); 2875bbf33d1dSEdwin Peer req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 2876bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2877bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 28783ebf6f0aSRob Swindell if (rc == 0) { 28793ebf6f0aSRob Swindell if (index) 28803ebf6f0aSRob Swindell *index = le16_to_cpu(output->dir_idx); 28813ebf6f0aSRob Swindell if (item_length) 28823ebf6f0aSRob Swindell *item_length = le32_to_cpu(output->dir_item_length); 28833ebf6f0aSRob Swindell if (data_length) 28843ebf6f0aSRob Swindell *data_length = le32_to_cpu(output->dir_data_length); 28853ebf6f0aSRob Swindell } 2886bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 28873ebf6f0aSRob Swindell return rc; 28883ebf6f0aSRob Swindell } 28893ebf6f0aSRob Swindell 28903ebf6f0aSRob Swindell static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 28913ebf6f0aSRob Swindell { 28923ebf6f0aSRob Swindell char *retval = NULL; 28933ebf6f0aSRob Swindell char *p; 28943ebf6f0aSRob Swindell char *value; 28953ebf6f0aSRob Swindell int field = 0; 28963ebf6f0aSRob Swindell 28973ebf6f0aSRob Swindell if (datalen < 1) 28983ebf6f0aSRob Swindell return NULL; 28993ebf6f0aSRob Swindell /* null-terminate the log data (removing last '\n'): */ 29003ebf6f0aSRob Swindell data[datalen - 1] = 0; 29013ebf6f0aSRob Swindell for (p = data; *p != 0; p++) { 29023ebf6f0aSRob Swindell field = 0; 29033ebf6f0aSRob Swindell retval = NULL; 29043ebf6f0aSRob Swindell while (*p != 0 && *p != '\n') { 29053ebf6f0aSRob Swindell value = p; 29063ebf6f0aSRob Swindell while (*p != 0 && *p != '\t' && *p != '\n') 29073ebf6f0aSRob Swindell p++; 29083ebf6f0aSRob Swindell if (field == desired_field) 29093ebf6f0aSRob Swindell retval = value; 29103ebf6f0aSRob Swindell if (*p != '\t') 29113ebf6f0aSRob Swindell break; 29123ebf6f0aSRob Swindell *p = 0; 29133ebf6f0aSRob Swindell field++; 29143ebf6f0aSRob Swindell p++; 29153ebf6f0aSRob Swindell } 29163ebf6f0aSRob Swindell if (*p == 0) 29173ebf6f0aSRob Swindell break; 29183ebf6f0aSRob Swindell *p = 0; 29193ebf6f0aSRob Swindell } 29203ebf6f0aSRob Swindell return retval; 29213ebf6f0aSRob Swindell } 29223ebf6f0aSRob Swindell 292363185eb3SVikas Gupta int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 29243ebf6f0aSRob Swindell { 2925a60faa60SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 29263ebf6f0aSRob Swindell u16 index = 0; 2927a60faa60SVasundhara Volam char *pkgver; 2928a60faa60SVasundhara Volam u32 pkglen; 2929a60faa60SVasundhara Volam u8 *pkgbuf; 293063185eb3SVikas Gupta int rc; 29313ebf6f0aSRob Swindell 293263185eb3SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 29333ebf6f0aSRob Swindell BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 293463185eb3SVikas Gupta &index, NULL, &pkglen); 293563185eb3SVikas Gupta if (rc) 293663185eb3SVikas Gupta return rc; 29373ebf6f0aSRob Swindell 2938a60faa60SVasundhara Volam pkgbuf = kzalloc(pkglen, GFP_KERNEL); 2939a60faa60SVasundhara Volam if (!pkgbuf) { 2940a60faa60SVasundhara Volam dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 2941a60faa60SVasundhara Volam pkglen); 294263185eb3SVikas Gupta return -ENOMEM; 2943a60faa60SVasundhara Volam } 29443ebf6f0aSRob Swindell 294563185eb3SVikas Gupta rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 294663185eb3SVikas Gupta if (rc) 2947a60faa60SVasundhara Volam goto err; 2948a60faa60SVasundhara Volam 2949a60faa60SVasundhara Volam pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 2950a60faa60SVasundhara Volam pkglen); 295163185eb3SVikas Gupta if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 295263185eb3SVikas Gupta strscpy(ver, pkgver, size); 295363185eb3SVikas Gupta else 295463185eb3SVikas Gupta rc = -ENOENT; 295563185eb3SVikas Gupta 2956a60faa60SVasundhara Volam err: 2957a60faa60SVasundhara Volam kfree(pkgbuf); 295863185eb3SVikas Gupta 295963185eb3SVikas Gupta return rc; 296063185eb3SVikas Gupta } 296163185eb3SVikas Gupta 296263185eb3SVikas Gupta static void bnxt_get_pkgver(struct net_device *dev) 296363185eb3SVikas Gupta { 296463185eb3SVikas Gupta struct bnxt *bp = netdev_priv(dev); 296563185eb3SVikas Gupta char buf[FW_VER_STR_LEN]; 296663185eb3SVikas Gupta int len; 296763185eb3SVikas Gupta 296863185eb3SVikas Gupta if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 296963185eb3SVikas Gupta len = strlen(bp->fw_ver_str); 297063185eb3SVikas Gupta snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 297163185eb3SVikas Gupta "/pkg %s", buf); 297263185eb3SVikas Gupta } 29733ebf6f0aSRob Swindell } 29743ebf6f0aSRob Swindell 2975c0c050c5SMichael Chan static int bnxt_get_eeprom(struct net_device *dev, 2976c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 2977c0c050c5SMichael Chan u8 *data) 2978c0c050c5SMichael Chan { 2979c0c050c5SMichael Chan u32 index; 2980c0c050c5SMichael Chan u32 offset; 2981c0c050c5SMichael Chan 2982c0c050c5SMichael Chan if (eeprom->offset == 0) /* special offset value to get directory */ 2983c0c050c5SMichael Chan return bnxt_get_nvram_directory(dev, eeprom->len, data); 2984c0c050c5SMichael Chan 2985c0c050c5SMichael Chan index = eeprom->offset >> 24; 2986c0c050c5SMichael Chan offset = eeprom->offset & 0xffffff; 2987c0c050c5SMichael Chan 2988c0c050c5SMichael Chan if (index == 0) { 2989c0c050c5SMichael Chan netdev_err(dev, "unsupported index value: %d\n", index); 2990c0c050c5SMichael Chan return -EINVAL; 2991c0c050c5SMichael Chan } 2992c0c050c5SMichael Chan 2993c0c050c5SMichael Chan return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 2994c0c050c5SMichael Chan } 2995c0c050c5SMichael Chan 2996c0c050c5SMichael Chan static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 2997c0c050c5SMichael Chan { 2998bbf33d1dSEdwin Peer struct hwrm_nvm_erase_dir_entry_input *req; 2999c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3000bbf33d1dSEdwin Peer int rc; 3001c0c050c5SMichael Chan 3002bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 3003bbf33d1dSEdwin Peer if (rc) 3004bbf33d1dSEdwin Peer return rc; 3005bbf33d1dSEdwin Peer 3006bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 3007bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3008c0c050c5SMichael Chan } 3009c0c050c5SMichael Chan 3010c0c050c5SMichael Chan static int bnxt_set_eeprom(struct net_device *dev, 3011c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 3012c0c050c5SMichael Chan u8 *data) 3013c0c050c5SMichael Chan { 3014c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3015c0c050c5SMichael Chan u8 index, dir_op; 3016c0c050c5SMichael Chan u16 type, ext, ordinal, attr; 3017c0c050c5SMichael Chan 3018c0c050c5SMichael Chan if (!BNXT_PF(bp)) { 3019c0c050c5SMichael Chan netdev_err(dev, "NVM write not supported from a virtual function\n"); 3020c0c050c5SMichael Chan return -EINVAL; 3021c0c050c5SMichael Chan } 3022c0c050c5SMichael Chan 3023c0c050c5SMichael Chan type = eeprom->magic >> 16; 3024c0c050c5SMichael Chan 3025c0c050c5SMichael Chan if (type == 0xffff) { /* special value for directory operations */ 3026c0c050c5SMichael Chan index = eeprom->magic & 0xff; 3027c0c050c5SMichael Chan dir_op = eeprom->magic >> 8; 3028c0c050c5SMichael Chan if (index == 0) 3029c0c050c5SMichael Chan return -EINVAL; 3030c0c050c5SMichael Chan switch (dir_op) { 3031c0c050c5SMichael Chan case 0x0e: /* erase */ 3032c0c050c5SMichael Chan if (eeprom->offset != ~eeprom->magic) 3033c0c050c5SMichael Chan return -EINVAL; 3034c0c050c5SMichael Chan return bnxt_erase_nvram_directory(dev, index - 1); 3035c0c050c5SMichael Chan default: 3036c0c050c5SMichael Chan return -EINVAL; 3037c0c050c5SMichael Chan } 3038c0c050c5SMichael Chan } 3039c0c050c5SMichael Chan 3040c0c050c5SMichael Chan /* Create or re-write an NVM item: */ 3041ba425800SJason Yan if (bnxt_dir_type_is_executable(type)) 30425ac67d8bSRob Swindell return -EOPNOTSUPP; 3043c0c050c5SMichael Chan ext = eeprom->magic & 0xffff; 3044c0c050c5SMichael Chan ordinal = eeprom->offset >> 16; 3045c0c050c5SMichael Chan attr = eeprom->offset & 0xffff; 3046c0c050c5SMichael Chan 3047bbf33d1dSEdwin Peer return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 3048c0c050c5SMichael Chan eeprom->len); 3049c0c050c5SMichael Chan } 3050c0c050c5SMichael Chan 305172b34f04SMichael Chan static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 305272b34f04SMichael Chan { 305372b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 305472b34f04SMichael Chan struct ethtool_eee *eee = &bp->eee; 305572b34f04SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 3056a5390690SMichael Chan u32 advertising; 305772b34f04SMichael Chan int rc = 0; 305872b34f04SMichael Chan 3059c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 306075362a3fSMichael Chan return -EOPNOTSUPP; 306172b34f04SMichael Chan 3062b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 306372b34f04SMichael Chan return -EOPNOTSUPP; 306472b34f04SMichael Chan 3065a5390690SMichael Chan mutex_lock(&bp->link_lock); 3066a5390690SMichael Chan advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 306772b34f04SMichael Chan if (!edata->eee_enabled) 306872b34f04SMichael Chan goto eee_ok; 306972b34f04SMichael Chan 307072b34f04SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 307172b34f04SMichael Chan netdev_warn(dev, "EEE requires autoneg\n"); 3072a5390690SMichael Chan rc = -EINVAL; 3073a5390690SMichael Chan goto eee_exit; 307472b34f04SMichael Chan } 307572b34f04SMichael Chan if (edata->tx_lpi_enabled) { 307672b34f04SMichael Chan if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 307772b34f04SMichael Chan edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 307872b34f04SMichael Chan netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 307972b34f04SMichael Chan bp->lpi_tmr_lo, bp->lpi_tmr_hi); 3080a5390690SMichael Chan rc = -EINVAL; 3081a5390690SMichael Chan goto eee_exit; 308272b34f04SMichael Chan } else if (!bp->lpi_tmr_hi) { 308372b34f04SMichael Chan edata->tx_lpi_timer = eee->tx_lpi_timer; 308472b34f04SMichael Chan } 308572b34f04SMichael Chan } 308672b34f04SMichael Chan if (!edata->advertised) { 308772b34f04SMichael Chan edata->advertised = advertising & eee->supported; 308872b34f04SMichael Chan } else if (edata->advertised & ~advertising) { 308972b34f04SMichael Chan netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 309072b34f04SMichael Chan edata->advertised, advertising); 3091a5390690SMichael Chan rc = -EINVAL; 3092a5390690SMichael Chan goto eee_exit; 309372b34f04SMichael Chan } 309472b34f04SMichael Chan 309572b34f04SMichael Chan eee->advertised = edata->advertised; 309672b34f04SMichael Chan eee->tx_lpi_enabled = edata->tx_lpi_enabled; 309772b34f04SMichael Chan eee->tx_lpi_timer = edata->tx_lpi_timer; 309872b34f04SMichael Chan eee_ok: 309972b34f04SMichael Chan eee->eee_enabled = edata->eee_enabled; 310072b34f04SMichael Chan 310172b34f04SMichael Chan if (netif_running(dev)) 310272b34f04SMichael Chan rc = bnxt_hwrm_set_link_setting(bp, false, true); 310372b34f04SMichael Chan 3104a5390690SMichael Chan eee_exit: 3105a5390690SMichael Chan mutex_unlock(&bp->link_lock); 310672b34f04SMichael Chan return rc; 310772b34f04SMichael Chan } 310872b34f04SMichael Chan 310972b34f04SMichael Chan static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 311072b34f04SMichael Chan { 311172b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 311272b34f04SMichael Chan 3113b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 311472b34f04SMichael Chan return -EOPNOTSUPP; 311572b34f04SMichael Chan 311672b34f04SMichael Chan *edata = bp->eee; 311772b34f04SMichael Chan if (!bp->eee.eee_enabled) { 311872b34f04SMichael Chan /* Preserve tx_lpi_timer so that the last value will be used 311972b34f04SMichael Chan * by default when it is re-enabled. 312072b34f04SMichael Chan */ 312172b34f04SMichael Chan edata->advertised = 0; 312272b34f04SMichael Chan edata->tx_lpi_enabled = 0; 312372b34f04SMichael Chan } 312472b34f04SMichael Chan 312572b34f04SMichael Chan if (!bp->eee.eee_active) 312672b34f04SMichael Chan edata->lp_advertised = 0; 312772b34f04SMichael Chan 312872b34f04SMichael Chan return 0; 312972b34f04SMichael Chan } 313072b34f04SMichael Chan 313142ee18feSAjit Khaparde static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 313242ee18feSAjit Khaparde u16 page_number, u16 start_addr, 313342ee18feSAjit Khaparde u16 data_length, u8 *buf) 313442ee18feSAjit Khaparde { 3135bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_output *output; 3136bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_input *req; 313742ee18feSAjit Khaparde int rc, byte_offset = 0; 313842ee18feSAjit Khaparde 3139bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 3140bbf33d1dSEdwin Peer if (rc) 3141bbf33d1dSEdwin Peer return rc; 3142bbf33d1dSEdwin Peer 3143bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 3144bbf33d1dSEdwin Peer req->i2c_slave_addr = i2c_addr; 3145bbf33d1dSEdwin Peer req->page_number = cpu_to_le16(page_number); 3146bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(bp->pf.port_id); 314742ee18feSAjit Khaparde do { 314842ee18feSAjit Khaparde u16 xfer_size; 314942ee18feSAjit Khaparde 315042ee18feSAjit Khaparde xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 315142ee18feSAjit Khaparde data_length -= xfer_size; 3152bbf33d1dSEdwin Peer req->page_offset = cpu_to_le16(start_addr + byte_offset); 3153bbf33d1dSEdwin Peer req->data_length = xfer_size; 3154bbf33d1dSEdwin Peer req->enables = cpu_to_le32(start_addr + byte_offset ? 315542ee18feSAjit Khaparde PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); 3156bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 315742ee18feSAjit Khaparde if (!rc) 315842ee18feSAjit Khaparde memcpy(buf + byte_offset, output->data, xfer_size); 315942ee18feSAjit Khaparde byte_offset += xfer_size; 316042ee18feSAjit Khaparde } while (!rc && data_length > 0); 3161bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 316242ee18feSAjit Khaparde 316342ee18feSAjit Khaparde return rc; 316442ee18feSAjit Khaparde } 316542ee18feSAjit Khaparde 316642ee18feSAjit Khaparde static int bnxt_get_module_info(struct net_device *dev, 316742ee18feSAjit Khaparde struct ethtool_modinfo *modinfo) 316842ee18feSAjit Khaparde { 31697328a23cSVasundhara Volam u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 317042ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 317142ee18feSAjit Khaparde int rc; 317242ee18feSAjit Khaparde 317342ee18feSAjit Khaparde /* No point in going further if phy status indicates 317442ee18feSAjit Khaparde * module is not inserted or if it is powered down or 317542ee18feSAjit Khaparde * if it is of type 10GBase-T 317642ee18feSAjit Khaparde */ 317742ee18feSAjit Khaparde if (bp->link_info.module_status > 317842ee18feSAjit Khaparde PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 317942ee18feSAjit Khaparde return -EOPNOTSUPP; 318042ee18feSAjit Khaparde 318142ee18feSAjit Khaparde /* This feature is not supported in older firmware versions */ 318242ee18feSAjit Khaparde if (bp->hwrm_spec_code < 0x10202) 318342ee18feSAjit Khaparde return -EOPNOTSUPP; 318442ee18feSAjit Khaparde 31857328a23cSVasundhara Volam rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 31867328a23cSVasundhara Volam SFF_DIAG_SUPPORT_OFFSET + 1, 31877328a23cSVasundhara Volam data); 318842ee18feSAjit Khaparde if (!rc) { 31897328a23cSVasundhara Volam u8 module_id = data[0]; 31907328a23cSVasundhara Volam u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 319142ee18feSAjit Khaparde 319242ee18feSAjit Khaparde switch (module_id) { 319342ee18feSAjit Khaparde case SFF_MODULE_ID_SFP: 319442ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8472; 319542ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 31967328a23cSVasundhara Volam if (!diag_supported) 31977328a23cSVasundhara Volam modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 319842ee18feSAjit Khaparde break; 319942ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP: 320042ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP_PLUS: 320142ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8436; 320242ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 320342ee18feSAjit Khaparde break; 320442ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP28: 320542ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8636; 320642ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 320742ee18feSAjit Khaparde break; 320842ee18feSAjit Khaparde default: 320942ee18feSAjit Khaparde rc = -EOPNOTSUPP; 321042ee18feSAjit Khaparde break; 321142ee18feSAjit Khaparde } 321242ee18feSAjit Khaparde } 321342ee18feSAjit Khaparde return rc; 321442ee18feSAjit Khaparde } 321542ee18feSAjit Khaparde 321642ee18feSAjit Khaparde static int bnxt_get_module_eeprom(struct net_device *dev, 321742ee18feSAjit Khaparde struct ethtool_eeprom *eeprom, 321842ee18feSAjit Khaparde u8 *data) 321942ee18feSAjit Khaparde { 322042ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 322142ee18feSAjit Khaparde u16 start = eeprom->offset, length = eeprom->len; 3222f3ea3119SColin Ian King int rc = 0; 322342ee18feSAjit Khaparde 322442ee18feSAjit Khaparde memset(data, 0, eeprom->len); 322542ee18feSAjit Khaparde 322642ee18feSAjit Khaparde /* Read A0 portion of the EEPROM */ 322742ee18feSAjit Khaparde if (start < ETH_MODULE_SFF_8436_LEN) { 322842ee18feSAjit Khaparde if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 322942ee18feSAjit Khaparde length = ETH_MODULE_SFF_8436_LEN - start; 323042ee18feSAjit Khaparde rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 323142ee18feSAjit Khaparde start, length, data); 323242ee18feSAjit Khaparde if (rc) 323342ee18feSAjit Khaparde return rc; 323442ee18feSAjit Khaparde start += length; 323542ee18feSAjit Khaparde data += length; 323642ee18feSAjit Khaparde length = eeprom->len - length; 323742ee18feSAjit Khaparde } 323842ee18feSAjit Khaparde 323942ee18feSAjit Khaparde /* Read A2 portion of the EEPROM */ 324042ee18feSAjit Khaparde if (length) { 324142ee18feSAjit Khaparde start -= ETH_MODULE_SFF_8436_LEN; 32424260330bSEdwin Peer rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 3243dea521a2SChristophe JAILLET start, length, data); 324442ee18feSAjit Khaparde } 324542ee18feSAjit Khaparde return rc; 324642ee18feSAjit Khaparde } 324742ee18feSAjit Khaparde 3248ae8e98a6SDeepak Khungar static int bnxt_nway_reset(struct net_device *dev) 3249ae8e98a6SDeepak Khungar { 3250ae8e98a6SDeepak Khungar int rc = 0; 3251ae8e98a6SDeepak Khungar 3252ae8e98a6SDeepak Khungar struct bnxt *bp = netdev_priv(dev); 3253ae8e98a6SDeepak Khungar struct bnxt_link_info *link_info = &bp->link_info; 3254ae8e98a6SDeepak Khungar 3255c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 3256ae8e98a6SDeepak Khungar return -EOPNOTSUPP; 3257ae8e98a6SDeepak Khungar 3258ae8e98a6SDeepak Khungar if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 3259ae8e98a6SDeepak Khungar return -EINVAL; 3260ae8e98a6SDeepak Khungar 3261ae8e98a6SDeepak Khungar if (netif_running(dev)) 3262ae8e98a6SDeepak Khungar rc = bnxt_hwrm_set_link_setting(bp, true, false); 3263ae8e98a6SDeepak Khungar 3264ae8e98a6SDeepak Khungar return rc; 3265ae8e98a6SDeepak Khungar } 3266ae8e98a6SDeepak Khungar 32675ad2cbeeSMichael Chan static int bnxt_set_phys_id(struct net_device *dev, 32685ad2cbeeSMichael Chan enum ethtool_phys_id_state state) 32695ad2cbeeSMichael Chan { 3270bbf33d1dSEdwin Peer struct hwrm_port_led_cfg_input *req; 32715ad2cbeeSMichael Chan struct bnxt *bp = netdev_priv(dev); 32725ad2cbeeSMichael Chan struct bnxt_pf_info *pf = &bp->pf; 32735ad2cbeeSMichael Chan struct bnxt_led_cfg *led_cfg; 32745ad2cbeeSMichael Chan u8 led_state; 32755ad2cbeeSMichael Chan __le16 duration; 3276bbf33d1dSEdwin Peer int rc, i; 32775ad2cbeeSMichael Chan 32785ad2cbeeSMichael Chan if (!bp->num_leds || BNXT_VF(bp)) 32795ad2cbeeSMichael Chan return -EOPNOTSUPP; 32805ad2cbeeSMichael Chan 32815ad2cbeeSMichael Chan if (state == ETHTOOL_ID_ACTIVE) { 32825ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 32835ad2cbeeSMichael Chan duration = cpu_to_le16(500); 32845ad2cbeeSMichael Chan } else if (state == ETHTOOL_ID_INACTIVE) { 32855ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 32865ad2cbeeSMichael Chan duration = cpu_to_le16(0); 32875ad2cbeeSMichael Chan } else { 32885ad2cbeeSMichael Chan return -EINVAL; 32895ad2cbeeSMichael Chan } 3290bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 3291bbf33d1dSEdwin Peer if (rc) 3292bbf33d1dSEdwin Peer return rc; 3293bbf33d1dSEdwin Peer 3294bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(pf->port_id); 3295bbf33d1dSEdwin Peer req->num_leds = bp->num_leds; 3296bbf33d1dSEdwin Peer led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 32975ad2cbeeSMichael Chan for (i = 0; i < bp->num_leds; i++, led_cfg++) { 3298bbf33d1dSEdwin Peer req->enables |= BNXT_LED_DFLT_ENABLES(i); 32995ad2cbeeSMichael Chan led_cfg->led_id = bp->leds[i].led_id; 33005ad2cbeeSMichael Chan led_cfg->led_state = led_state; 33015ad2cbeeSMichael Chan led_cfg->led_blink_on = duration; 33025ad2cbeeSMichael Chan led_cfg->led_blink_off = duration; 33035ad2cbeeSMichael Chan led_cfg->led_group_id = bp->leds[i].led_group_id; 33045ad2cbeeSMichael Chan } 3305bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 33065ad2cbeeSMichael Chan } 33075ad2cbeeSMichael Chan 330867fea463SMichael Chan static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 330967fea463SMichael Chan { 3310bbf33d1dSEdwin Peer struct hwrm_selftest_irq_input *req; 3311bbf33d1dSEdwin Peer int rc; 331267fea463SMichael Chan 3313bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 3314bbf33d1dSEdwin Peer if (rc) 3315bbf33d1dSEdwin Peer return rc; 3316bbf33d1dSEdwin Peer 3317bbf33d1dSEdwin Peer req->cmpl_ring = cpu_to_le16(cmpl_ring); 3318bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 331967fea463SMichael Chan } 332067fea463SMichael Chan 332167fea463SMichael Chan static int bnxt_test_irq(struct bnxt *bp) 332267fea463SMichael Chan { 332367fea463SMichael Chan int i; 332467fea463SMichael Chan 332567fea463SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 332667fea463SMichael Chan u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 332767fea463SMichael Chan int rc; 332867fea463SMichael Chan 332967fea463SMichael Chan rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 333067fea463SMichael Chan if (rc) 333167fea463SMichael Chan return rc; 333267fea463SMichael Chan } 333367fea463SMichael Chan return 0; 333467fea463SMichael Chan } 333567fea463SMichael Chan 3336f7dc1ea6SMichael Chan static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 3337f7dc1ea6SMichael Chan { 3338bbf33d1dSEdwin Peer struct hwrm_port_mac_cfg_input *req; 3339bbf33d1dSEdwin Peer int rc; 3340f7dc1ea6SMichael Chan 3341bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 3342bbf33d1dSEdwin Peer if (rc) 3343bbf33d1dSEdwin Peer return rc; 3344f7dc1ea6SMichael Chan 3345bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 3346f7dc1ea6SMichael Chan if (enable) 3347bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 3348f7dc1ea6SMichael Chan else 3349bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 3350bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3351f7dc1ea6SMichael Chan } 3352f7dc1ea6SMichael Chan 335356d37462SVasundhara Volam static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 335456d37462SVasundhara Volam { 3355bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_output *resp; 3356bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_input *req; 335756d37462SVasundhara Volam int rc; 335856d37462SVasundhara Volam 3359bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 3360bbf33d1dSEdwin Peer if (rc) 3361bbf33d1dSEdwin Peer return rc; 3362bbf33d1dSEdwin Peer 3363bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3364bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 336556d37462SVasundhara Volam if (!rc) 336656d37462SVasundhara Volam *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 336756d37462SVasundhara Volam 3368bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 336956d37462SVasundhara Volam return rc; 337056d37462SVasundhara Volam } 337156d37462SVasundhara Volam 337291725d89SMichael Chan static int bnxt_disable_an_for_lpbk(struct bnxt *bp, 337391725d89SMichael Chan struct hwrm_port_phy_cfg_input *req) 337491725d89SMichael Chan { 337591725d89SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 337656d37462SVasundhara Volam u16 fw_advertising; 337791725d89SMichael Chan u16 fw_speed; 337891725d89SMichael Chan int rc; 337991725d89SMichael Chan 33808a60efd1SMichael Chan if (!link_info->autoneg || 3381b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 338291725d89SMichael Chan return 0; 338391725d89SMichael Chan 338456d37462SVasundhara Volam rc = bnxt_query_force_speeds(bp, &fw_advertising); 338556d37462SVasundhara Volam if (rc) 338656d37462SVasundhara Volam return rc; 338756d37462SVasundhara Volam 338891725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 33890f5a4841SEdwin Peer if (BNXT_LINK_IS_UP(bp)) 339091725d89SMichael Chan fw_speed = bp->link_info.link_speed; 339191725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 339291725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 339391725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 339491725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 339591725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 339691725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 339791725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 339891725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 339991725d89SMichael Chan 340091725d89SMichael Chan req->force_link_speed = cpu_to_le16(fw_speed); 340191725d89SMichael Chan req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 340291725d89SMichael Chan PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 3403bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 340491725d89SMichael Chan req->flags = 0; 340591725d89SMichael Chan req->force_link_speed = cpu_to_le16(0); 340691725d89SMichael Chan return rc; 340791725d89SMichael Chan } 340891725d89SMichael Chan 340955fd0cf3SMichael Chan static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 341091725d89SMichael Chan { 3411bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 3412bbf33d1dSEdwin Peer int rc; 341391725d89SMichael Chan 3414bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 3415bbf33d1dSEdwin Peer if (rc) 3416bbf33d1dSEdwin Peer return rc; 3417bbf33d1dSEdwin Peer 3418bbf33d1dSEdwin Peer /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 3419bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 342091725d89SMichael Chan 342191725d89SMichael Chan if (enable) { 3422bbf33d1dSEdwin Peer bnxt_disable_an_for_lpbk(bp, req); 342355fd0cf3SMichael Chan if (ext) 3424bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 342555fd0cf3SMichael Chan else 3426bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 342791725d89SMichael Chan } else { 3428bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 342991725d89SMichael Chan } 3430bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 3431bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3432bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3433bbf33d1dSEdwin Peer return rc; 343491725d89SMichael Chan } 343591725d89SMichael Chan 3436e44758b7SMichael Chan static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3437f7dc1ea6SMichael Chan u32 raw_cons, int pkt_size) 3438f7dc1ea6SMichael Chan { 3439e44758b7SMichael Chan struct bnxt_napi *bnapi = cpr->bnapi; 3440e44758b7SMichael Chan struct bnxt_rx_ring_info *rxr; 3441f7dc1ea6SMichael Chan struct bnxt_sw_rx_bd *rx_buf; 3442f7dc1ea6SMichael Chan struct rx_cmp *rxcmp; 3443f7dc1ea6SMichael Chan u16 cp_cons, cons; 3444f7dc1ea6SMichael Chan u8 *data; 3445f7dc1ea6SMichael Chan u32 len; 3446f7dc1ea6SMichael Chan int i; 3447f7dc1ea6SMichael Chan 3448e44758b7SMichael Chan rxr = bnapi->rx_ring; 3449f7dc1ea6SMichael Chan cp_cons = RING_CMP(raw_cons); 3450f7dc1ea6SMichael Chan rxcmp = (struct rx_cmp *) 3451f7dc1ea6SMichael Chan &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 3452f7dc1ea6SMichael Chan cons = rxcmp->rx_cmp_opaque; 3453f7dc1ea6SMichael Chan rx_buf = &rxr->rx_buf_ring[cons]; 3454f7dc1ea6SMichael Chan data = rx_buf->data_ptr; 3455f7dc1ea6SMichael Chan len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 3456f7dc1ea6SMichael Chan if (len != pkt_size) 3457f7dc1ea6SMichael Chan return -EIO; 3458f7dc1ea6SMichael Chan i = ETH_ALEN; 3459f7dc1ea6SMichael Chan if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 3460f7dc1ea6SMichael Chan return -EIO; 3461f7dc1ea6SMichael Chan i += ETH_ALEN; 3462f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) { 3463f7dc1ea6SMichael Chan if (data[i] != (u8)(i & 0xff)) 3464f7dc1ea6SMichael Chan return -EIO; 3465f7dc1ea6SMichael Chan } 3466f7dc1ea6SMichael Chan return 0; 3467f7dc1ea6SMichael Chan } 3468f7dc1ea6SMichael Chan 3469e44758b7SMichael Chan static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3470e44758b7SMichael Chan int pkt_size) 3471f7dc1ea6SMichael Chan { 3472f7dc1ea6SMichael Chan struct tx_cmp *txcmp; 3473f7dc1ea6SMichael Chan int rc = -EIO; 3474f7dc1ea6SMichael Chan u32 raw_cons; 3475f7dc1ea6SMichael Chan u32 cons; 3476f7dc1ea6SMichael Chan int i; 3477f7dc1ea6SMichael Chan 3478f7dc1ea6SMichael Chan raw_cons = cpr->cp_raw_cons; 3479f7dc1ea6SMichael Chan for (i = 0; i < 200; i++) { 3480f7dc1ea6SMichael Chan cons = RING_CMP(raw_cons); 3481f7dc1ea6SMichael Chan txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 3482f7dc1ea6SMichael Chan 3483f7dc1ea6SMichael Chan if (!TX_CMP_VALID(txcmp, raw_cons)) { 3484f7dc1ea6SMichael Chan udelay(5); 3485f7dc1ea6SMichael Chan continue; 3486f7dc1ea6SMichael Chan } 3487f7dc1ea6SMichael Chan 3488f7dc1ea6SMichael Chan /* The valid test of the entry must be done first before 3489f7dc1ea6SMichael Chan * reading any further. 3490f7dc1ea6SMichael Chan */ 3491f7dc1ea6SMichael Chan dma_rmb(); 3492f7dc1ea6SMichael Chan if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 3493e44758b7SMichael Chan rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 3494f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3495f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3496f7dc1ea6SMichael Chan break; 3497f7dc1ea6SMichael Chan } 3498f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3499f7dc1ea6SMichael Chan } 3500f7dc1ea6SMichael Chan cpr->cp_raw_cons = raw_cons; 3501f7dc1ea6SMichael Chan return rc; 3502f7dc1ea6SMichael Chan } 3503f7dc1ea6SMichael Chan 3504f7dc1ea6SMichael Chan static int bnxt_run_loopback(struct bnxt *bp) 3505f7dc1ea6SMichael Chan { 3506f7dc1ea6SMichael Chan struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 350784404d5fSMichael Chan struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 3508e44758b7SMichael Chan struct bnxt_cp_ring_info *cpr; 3509f7dc1ea6SMichael Chan int pkt_size, i = 0; 3510f7dc1ea6SMichael Chan struct sk_buff *skb; 3511f7dc1ea6SMichael Chan dma_addr_t map; 3512f7dc1ea6SMichael Chan u8 *data; 3513f7dc1ea6SMichael Chan int rc; 3514f7dc1ea6SMichael Chan 351584404d5fSMichael Chan cpr = &rxr->bnapi->cp_ring; 351684404d5fSMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 351784404d5fSMichael Chan cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 3518f7dc1ea6SMichael Chan pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 3519f7dc1ea6SMichael Chan skb = netdev_alloc_skb(bp->dev, pkt_size); 3520f7dc1ea6SMichael Chan if (!skb) 3521f7dc1ea6SMichael Chan return -ENOMEM; 3522f7dc1ea6SMichael Chan data = skb_put(skb, pkt_size); 3523cfcab3b3SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3524f7dc1ea6SMichael Chan i += ETH_ALEN; 3525f7dc1ea6SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3526f7dc1ea6SMichael Chan i += ETH_ALEN; 3527f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) 3528f7dc1ea6SMichael Chan data[i] = (u8)(i & 0xff); 3529f7dc1ea6SMichael Chan 3530f7dc1ea6SMichael Chan map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 3531df70303dSChristophe JAILLET DMA_TO_DEVICE); 3532f7dc1ea6SMichael Chan if (dma_mapping_error(&bp->pdev->dev, map)) { 3533f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3534f7dc1ea6SMichael Chan return -EIO; 3535f7dc1ea6SMichael Chan } 3536c1ba92a8SMichael Chan bnxt_xmit_bd(bp, txr, map, pkt_size); 3537f7dc1ea6SMichael Chan 3538f7dc1ea6SMichael Chan /* Sync BD data before updating doorbell */ 3539f7dc1ea6SMichael Chan wmb(); 3540f7dc1ea6SMichael Chan 3541697197e5SMichael Chan bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 3542e44758b7SMichael Chan rc = bnxt_poll_loopback(bp, cpr, pkt_size); 3543f7dc1ea6SMichael Chan 3544df70303dSChristophe JAILLET dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 3545f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3546f7dc1ea6SMichael Chan return rc; 3547f7dc1ea6SMichael Chan } 3548f7dc1ea6SMichael Chan 3549eb513658SMichael Chan static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 3550eb513658SMichael Chan { 3551bbf33d1dSEdwin Peer struct hwrm_selftest_exec_output *resp; 3552bbf33d1dSEdwin Peer struct hwrm_selftest_exec_input *req; 3553eb513658SMichael Chan int rc; 3554eb513658SMichael Chan 3555bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 3556bbf33d1dSEdwin Peer if (rc) 3557bbf33d1dSEdwin Peer return rc; 3558bbf33d1dSEdwin Peer 3559bbf33d1dSEdwin Peer hwrm_req_timeout(bp, req, bp->test_info->timeout); 3560bbf33d1dSEdwin Peer req->flags = test_mask; 3561bbf33d1dSEdwin Peer 3562bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3563bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3564eb513658SMichael Chan *test_results = resp->test_success; 3565bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3566eb513658SMichael Chan return rc; 3567eb513658SMichael Chan } 3568eb513658SMichael Chan 356955fd0cf3SMichael Chan #define BNXT_DRV_TESTS 4 3570f7dc1ea6SMichael Chan #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 357191725d89SMichael Chan #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 357255fd0cf3SMichael Chan #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 357355fd0cf3SMichael Chan #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 3574eb513658SMichael Chan 3575eb513658SMichael Chan static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 3576eb513658SMichael Chan u64 *buf) 3577eb513658SMichael Chan { 3578eb513658SMichael Chan struct bnxt *bp = netdev_priv(dev); 357955fd0cf3SMichael Chan bool do_ext_lpbk = false; 3580eb513658SMichael Chan bool offline = false; 3581eb513658SMichael Chan u8 test_results = 0; 3582eb513658SMichael Chan u8 test_mask = 0; 3583d27e2ca1SMichael Chan int rc = 0, i; 3584eb513658SMichael Chan 35856896cb35SVasundhara Volam if (!bp->num_tests || !BNXT_PF(bp)) 3586eb513658SMichael Chan return; 3587eb513658SMichael Chan memset(buf, 0, sizeof(u64) * bp->num_tests); 3588eb513658SMichael Chan if (!netif_running(dev)) { 3589eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3590eb513658SMichael Chan return; 3591eb513658SMichael Chan } 3592eb513658SMichael Chan 359355fd0cf3SMichael Chan if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 3594b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 359555fd0cf3SMichael Chan do_ext_lpbk = true; 359655fd0cf3SMichael Chan 3597eb513658SMichael Chan if (etest->flags & ETH_TEST_FL_OFFLINE) { 35986896cb35SVasundhara Volam if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 3599eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 36006896cb35SVasundhara Volam netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 3601eb513658SMichael Chan return; 3602eb513658SMichael Chan } 3603eb513658SMichael Chan offline = true; 3604eb513658SMichael Chan } 3605eb513658SMichael Chan 3606eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3607eb513658SMichael Chan u8 bit_val = 1 << i; 3608eb513658SMichael Chan 3609eb513658SMichael Chan if (!(bp->test_info->offline_mask & bit_val)) 3610eb513658SMichael Chan test_mask |= bit_val; 3611eb513658SMichael Chan else if (offline) 3612eb513658SMichael Chan test_mask |= bit_val; 3613eb513658SMichael Chan } 3614eb513658SMichael Chan if (!offline) { 3615eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3616eb513658SMichael Chan } else { 36176758f937SMichael Chan bnxt_ulp_stop(bp); 36186758f937SMichael Chan rc = bnxt_close_nic(bp, true, false); 36196758f937SMichael Chan if (rc) { 36206758f937SMichael Chan bnxt_ulp_start(bp, rc); 3621eb513658SMichael Chan return; 36226758f937SMichael Chan } 3623eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3624f7dc1ea6SMichael Chan 3625f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 1; 3626f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, true); 3627f7dc1ea6SMichael Chan msleep(250); 3628f7dc1ea6SMichael Chan rc = bnxt_half_open_nic(bp); 3629f7dc1ea6SMichael Chan if (rc) { 3630f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 3631f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 36326758f937SMichael Chan bnxt_ulp_start(bp, rc); 3633f7dc1ea6SMichael Chan return; 3634f7dc1ea6SMichael Chan } 3635f7dc1ea6SMichael Chan if (bnxt_run_loopback(bp)) 3636f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3637f7dc1ea6SMichael Chan else 3638f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 0; 3639f7dc1ea6SMichael Chan 3640f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 364155fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, false); 364291725d89SMichael Chan msleep(1000); 364391725d89SMichael Chan if (bnxt_run_loopback(bp)) { 364491725d89SMichael Chan buf[BNXT_PHYLPBK_TEST_IDX] = 1; 364591725d89SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 364691725d89SMichael Chan } 364755fd0cf3SMichael Chan if (do_ext_lpbk) { 364855fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 364955fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, true); 365055fd0cf3SMichael Chan msleep(1000); 365155fd0cf3SMichael Chan if (bnxt_run_loopback(bp)) { 365255fd0cf3SMichael Chan buf[BNXT_EXTLPBK_TEST_IDX] = 1; 365355fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 365455fd0cf3SMichael Chan } 365555fd0cf3SMichael Chan } 365655fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, false, false); 365791725d89SMichael Chan bnxt_half_close_nic(bp); 36586758f937SMichael Chan rc = bnxt_open_nic(bp, true, true); 36596758f937SMichael Chan bnxt_ulp_start(bp, rc); 3660eb513658SMichael Chan } 3661d27e2ca1SMichael Chan if (rc || bnxt_test_irq(bp)) { 366267fea463SMichael Chan buf[BNXT_IRQ_TEST_IDX] = 1; 366367fea463SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 366467fea463SMichael Chan } 3665eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3666eb513658SMichael Chan u8 bit_val = 1 << i; 3667eb513658SMichael Chan 3668eb513658SMichael Chan if ((test_mask & bit_val) && !(test_results & bit_val)) { 3669eb513658SMichael Chan buf[i] = 1; 3670eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3671eb513658SMichael Chan } 3672eb513658SMichael Chan } 3673eb513658SMichael Chan } 3674eb513658SMichael Chan 367549f7972fSVasundhara Volam static int bnxt_reset(struct net_device *dev, u32 *flags) 367649f7972fSVasundhara Volam { 367749f7972fSVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36788cec0940SEdwin Peer bool reload = false; 36797a13240eSEdwin Peer u32 req = *flags; 36807a13240eSEdwin Peer 36817a13240eSEdwin Peer if (!req) 36827a13240eSEdwin Peer return -EINVAL; 368349f7972fSVasundhara Volam 368449f7972fSVasundhara Volam if (!BNXT_PF(bp)) { 368549f7972fSVasundhara Volam netdev_err(dev, "Reset is not supported from a VF\n"); 368649f7972fSVasundhara Volam return -EOPNOTSUPP; 368749f7972fSVasundhara Volam } 368849f7972fSVasundhara Volam 36890a3f4e4fSVasundhara Volam if (pci_vfs_assigned(bp->pdev) && 36900a3f4e4fSVasundhara Volam !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 369149f7972fSVasundhara Volam netdev_err(dev, 369249f7972fSVasundhara Volam "Reset not allowed when VFs are assigned to VMs\n"); 369349f7972fSVasundhara Volam return -EBUSY; 369449f7972fSVasundhara Volam } 369549f7972fSVasundhara Volam 36967a13240eSEdwin Peer if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 369749f7972fSVasundhara Volam /* This feature is not supported in older firmware versions */ 36987a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 36997a13240eSEdwin Peer if (!bnxt_firmware_reset_chip(dev)) { 37007a13240eSEdwin Peer netdev_info(dev, "Firmware reset request successful.\n"); 37010a3f4e4fSVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 37028cec0940SEdwin Peer reload = true; 37037a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_CHIP; 37042373d8d6SScott Branden } 37057a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_CHIP) { 37067a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 37077a13240eSEdwin Peer } 37087a13240eSEdwin Peer } 37097a13240eSEdwin Peer 37107a13240eSEdwin Peer if (req & BNXT_FW_RESET_AP) { 37116502ad59SScott Branden /* This feature is not supported in older firmware versions */ 37127a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 37137a13240eSEdwin Peer if (!bnxt_firmware_reset_ap(dev)) { 37147a13240eSEdwin Peer netdev_info(dev, "Reset application processor successful.\n"); 37158cec0940SEdwin Peer reload = true; 37167a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_AP; 37172373d8d6SScott Branden } 37187a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_AP) { 37197a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 37207a13240eSEdwin Peer } 372149f7972fSVasundhara Volam } 372249f7972fSVasundhara Volam 37238cec0940SEdwin Peer if (reload) 37248cec0940SEdwin Peer netdev_info(dev, "Reload driver to complete reset\n"); 37258cec0940SEdwin Peer 37267a13240eSEdwin Peer return 0; 372749f7972fSVasundhara Volam } 372849f7972fSVasundhara Volam 37290b0eacf3SVasundhara Volam static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 37300b0eacf3SVasundhara Volam { 37310b0eacf3SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37320b0eacf3SVasundhara Volam 37330b0eacf3SVasundhara Volam if (dump->flag > BNXT_DUMP_CRASH) { 37340b0eacf3SVasundhara Volam netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 37350b0eacf3SVasundhara Volam return -EINVAL; 37360b0eacf3SVasundhara Volam } 37370b0eacf3SVasundhara Volam 37380b0eacf3SVasundhara Volam if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 37390b0eacf3SVasundhara Volam netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 37400b0eacf3SVasundhara Volam return -EOPNOTSUPP; 37410b0eacf3SVasundhara Volam } 37420b0eacf3SVasundhara Volam 37430b0eacf3SVasundhara Volam bp->dump_flag = dump->flag; 37440b0eacf3SVasundhara Volam return 0; 37450b0eacf3SVasundhara Volam } 37460b0eacf3SVasundhara Volam 37476c5657d0SVasundhara Volam static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 37486c5657d0SVasundhara Volam { 37496c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37506c5657d0SVasundhara Volam 37516c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 37526c5657d0SVasundhara Volam return -EOPNOTSUPP; 37536c5657d0SVasundhara Volam 37546c5657d0SVasundhara Volam dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 37556c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_min_8b << 16 | 37566c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_bld_8b << 8 | 37576c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_rsvd_8b; 37586c5657d0SVasundhara Volam 37590b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 37609a575c8cSEdwin Peer dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 37610b0eacf3SVasundhara Volam return 0; 37626c5657d0SVasundhara Volam } 37636c5657d0SVasundhara Volam 37646c5657d0SVasundhara Volam static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 37656c5657d0SVasundhara Volam void *buf) 37666c5657d0SVasundhara Volam { 37676c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37686c5657d0SVasundhara Volam 37696c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 37706c5657d0SVasundhara Volam return -EOPNOTSUPP; 37716c5657d0SVasundhara Volam 37726c5657d0SVasundhara Volam memset(buf, 0, dump->len); 37736c5657d0SVasundhara Volam 37740b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 37759a575c8cSEdwin Peer return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 37760b0eacf3SVasundhara Volam } 37770b0eacf3SVasundhara Volam 3778118612d5SMichael Chan static int bnxt_get_ts_info(struct net_device *dev, 3779118612d5SMichael Chan struct ethtool_ts_info *info) 3780118612d5SMichael Chan { 3781118612d5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3782118612d5SMichael Chan struct bnxt_ptp_cfg *ptp; 3783118612d5SMichael Chan 3784118612d5SMichael Chan ptp = bp->ptp_cfg; 3785118612d5SMichael Chan info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 3786118612d5SMichael Chan SOF_TIMESTAMPING_RX_SOFTWARE | 3787118612d5SMichael Chan SOF_TIMESTAMPING_SOFTWARE; 3788118612d5SMichael Chan 3789118612d5SMichael Chan info->phc_index = -1; 3790118612d5SMichael Chan if (!ptp) 3791118612d5SMichael Chan return 0; 3792118612d5SMichael Chan 3793118612d5SMichael Chan info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 3794118612d5SMichael Chan SOF_TIMESTAMPING_RX_HARDWARE | 3795118612d5SMichael Chan SOF_TIMESTAMPING_RAW_HARDWARE; 3796118612d5SMichael Chan if (ptp->ptp_clock) 3797118612d5SMichael Chan info->phc_index = ptp_clock_index(ptp->ptp_clock); 3798118612d5SMichael Chan 3799118612d5SMichael Chan info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 3800118612d5SMichael Chan 3801118612d5SMichael Chan info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 3802118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 3803118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 3804118612d5SMichael Chan return 0; 3805118612d5SMichael Chan } 3806118612d5SMichael Chan 3807eb513658SMichael Chan void bnxt_ethtool_init(struct bnxt *bp) 3808eb513658SMichael Chan { 3809bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_output *resp; 3810bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_input *req; 3811eb513658SMichael Chan struct bnxt_test_info *test_info; 3812431aa1ebSMichael Chan struct net_device *dev = bp->dev; 3813eb513658SMichael Chan int i, rc; 3814eb513658SMichael Chan 3815691aa620SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 3816a60faa60SVasundhara Volam bnxt_get_pkgver(dev); 3817431aa1ebSMichael Chan 3818ba642ab7SMichael Chan bp->num_tests = 0; 38196896cb35SVasundhara Volam if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 3820eb513658SMichael Chan return; 3821eb513658SMichael Chan 3822bbf33d1dSEdwin Peer test_info = bp->test_info; 3823bbf33d1dSEdwin Peer if (!test_info) { 3824bbf33d1dSEdwin Peer test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 3825bbf33d1dSEdwin Peer if (!test_info) 3826bbf33d1dSEdwin Peer return; 3827bbf33d1dSEdwin Peer bp->test_info = test_info; 3828bbf33d1dSEdwin Peer } 3829bbf33d1dSEdwin Peer 3830bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 3831bbf33d1dSEdwin Peer return; 3832bbf33d1dSEdwin Peer 3833bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3834bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 3835eb513658SMichael Chan if (rc) 3836eb513658SMichael Chan goto ethtool_init_exit; 3837eb513658SMichael Chan 3838eb513658SMichael Chan bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 3839eb513658SMichael Chan if (bp->num_tests > BNXT_MAX_TEST) 3840eb513658SMichael Chan bp->num_tests = BNXT_MAX_TEST; 3841eb513658SMichael Chan 3842eb513658SMichael Chan test_info->offline_mask = resp->offline_tests; 3843eb513658SMichael Chan test_info->timeout = le16_to_cpu(resp->test_timeout); 3844eb513658SMichael Chan if (!test_info->timeout) 3845eb513658SMichael Chan test_info->timeout = HWRM_CMD_TIMEOUT; 3846eb513658SMichael Chan for (i = 0; i < bp->num_tests; i++) { 3847eb513658SMichael Chan char *str = test_info->string[i]; 3848eb513658SMichael Chan char *fw_str = resp->test0_name + i * 32; 3849eb513658SMichael Chan 3850f7dc1ea6SMichael Chan if (i == BNXT_MACLPBK_TEST_IDX) { 3851f7dc1ea6SMichael Chan strcpy(str, "Mac loopback test (offline)"); 385291725d89SMichael Chan } else if (i == BNXT_PHYLPBK_TEST_IDX) { 385391725d89SMichael Chan strcpy(str, "Phy loopback test (offline)"); 385455fd0cf3SMichael Chan } else if (i == BNXT_EXTLPBK_TEST_IDX) { 385555fd0cf3SMichael Chan strcpy(str, "Ext loopback test (offline)"); 385667fea463SMichael Chan } else if (i == BNXT_IRQ_TEST_IDX) { 385767fea463SMichael Chan strcpy(str, "Interrupt_test (offline)"); 3858f7dc1ea6SMichael Chan } else { 3859eb513658SMichael Chan strlcpy(str, fw_str, ETH_GSTRING_LEN); 3860eb513658SMichael Chan strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); 3861eb513658SMichael Chan if (test_info->offline_mask & (1 << i)) 3862eb513658SMichael Chan strncat(str, " (offline)", 3863eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3864eb513658SMichael Chan else 3865eb513658SMichael Chan strncat(str, " (online)", 3866eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3867eb513658SMichael Chan } 3868f7dc1ea6SMichael Chan } 3869eb513658SMichael Chan 3870eb513658SMichael Chan ethtool_init_exit: 3871bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3872eb513658SMichael Chan } 3873eb513658SMichael Chan 3874782bc00aSJakub Kicinski static void bnxt_get_eth_phy_stats(struct net_device *dev, 3875782bc00aSJakub Kicinski struct ethtool_eth_phy_stats *phy_stats) 3876782bc00aSJakub Kicinski { 3877782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3878782bc00aSJakub Kicinski u64 *rx; 3879782bc00aSJakub Kicinski 3880782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 3881782bc00aSJakub Kicinski return; 3882782bc00aSJakub Kicinski 3883782bc00aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 3884782bc00aSJakub Kicinski phy_stats->SymbolErrorDuringCarrier = 3885782bc00aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 3886782bc00aSJakub Kicinski } 3887782bc00aSJakub Kicinski 3888782bc00aSJakub Kicinski static void bnxt_get_eth_mac_stats(struct net_device *dev, 3889782bc00aSJakub Kicinski struct ethtool_eth_mac_stats *mac_stats) 3890782bc00aSJakub Kicinski { 3891782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3892782bc00aSJakub Kicinski u64 *rx, *tx; 3893782bc00aSJakub Kicinski 3894782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3895782bc00aSJakub Kicinski return; 3896782bc00aSJakub Kicinski 3897782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3898782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3899782bc00aSJakub Kicinski 3900782bc00aSJakub Kicinski mac_stats->FramesReceivedOK = 3901782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 3902782bc00aSJakub Kicinski mac_stats->FramesTransmittedOK = 3903782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 390437434782SJakub Kicinski mac_stats->FrameCheckSequenceErrors = 390537434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 390637434782SJakub Kicinski mac_stats->AlignmentErrors = 390737434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 390837434782SJakub Kicinski mac_stats->OutOfRangeLengthField = 390937434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 3910782bc00aSJakub Kicinski } 3911782bc00aSJakub Kicinski 3912782bc00aSJakub Kicinski static void bnxt_get_eth_ctrl_stats(struct net_device *dev, 3913782bc00aSJakub Kicinski struct ethtool_eth_ctrl_stats *ctrl_stats) 3914782bc00aSJakub Kicinski { 3915782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3916782bc00aSJakub Kicinski u64 *rx; 3917782bc00aSJakub Kicinski 3918782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3919782bc00aSJakub Kicinski return; 3920782bc00aSJakub Kicinski 3921782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3922782bc00aSJakub Kicinski ctrl_stats->MACControlFramesReceived = 3923782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 3924782bc00aSJakub Kicinski } 3925782bc00aSJakub Kicinski 3926782bc00aSJakub Kicinski static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 3927782bc00aSJakub Kicinski { 0, 64 }, 3928782bc00aSJakub Kicinski { 65, 127 }, 3929782bc00aSJakub Kicinski { 128, 255 }, 3930782bc00aSJakub Kicinski { 256, 511 }, 3931782bc00aSJakub Kicinski { 512, 1023 }, 3932782bc00aSJakub Kicinski { 1024, 1518 }, 3933782bc00aSJakub Kicinski { 1519, 2047 }, 3934782bc00aSJakub Kicinski { 2048, 4095 }, 3935782bc00aSJakub Kicinski { 4096, 9216 }, 3936782bc00aSJakub Kicinski { 9217, 16383 }, 3937782bc00aSJakub Kicinski {} 3938782bc00aSJakub Kicinski }; 3939782bc00aSJakub Kicinski 3940782bc00aSJakub Kicinski static void bnxt_get_rmon_stats(struct net_device *dev, 3941782bc00aSJakub Kicinski struct ethtool_rmon_stats *rmon_stats, 3942782bc00aSJakub Kicinski const struct ethtool_rmon_hist_range **ranges) 3943782bc00aSJakub Kicinski { 3944782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3945782bc00aSJakub Kicinski u64 *rx, *tx; 3946782bc00aSJakub Kicinski 3947782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3948782bc00aSJakub Kicinski return; 3949782bc00aSJakub Kicinski 3950782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3951782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3952782bc00aSJakub Kicinski 3953782bc00aSJakub Kicinski rmon_stats->jabbers = 3954782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 3955782bc00aSJakub Kicinski rmon_stats->oversize_pkts = 3956782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 3957782bc00aSJakub Kicinski rmon_stats->undersize_pkts = 3958782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 3959782bc00aSJakub Kicinski 3960782bc00aSJakub Kicinski rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 3961782bc00aSJakub Kicinski rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 3962782bc00aSJakub Kicinski rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 3963782bc00aSJakub Kicinski rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 3964782bc00aSJakub Kicinski rmon_stats->hist[4] = 3965782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 3966782bc00aSJakub Kicinski rmon_stats->hist[5] = 3967782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 3968782bc00aSJakub Kicinski rmon_stats->hist[6] = 3969782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 3970782bc00aSJakub Kicinski rmon_stats->hist[7] = 3971782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 3972782bc00aSJakub Kicinski rmon_stats->hist[8] = 3973782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 3974782bc00aSJakub Kicinski rmon_stats->hist[9] = 3975782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 3976782bc00aSJakub Kicinski 3977782bc00aSJakub Kicinski rmon_stats->hist_tx[0] = 3978782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 3979782bc00aSJakub Kicinski rmon_stats->hist_tx[1] = 3980782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 3981782bc00aSJakub Kicinski rmon_stats->hist_tx[2] = 3982782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 3983782bc00aSJakub Kicinski rmon_stats->hist_tx[3] = 3984782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 3985782bc00aSJakub Kicinski rmon_stats->hist_tx[4] = 3986782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 3987782bc00aSJakub Kicinski rmon_stats->hist_tx[5] = 3988782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 3989782bc00aSJakub Kicinski rmon_stats->hist_tx[6] = 3990782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 3991782bc00aSJakub Kicinski rmon_stats->hist_tx[7] = 3992782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 3993782bc00aSJakub Kicinski rmon_stats->hist_tx[8] = 3994782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 3995782bc00aSJakub Kicinski rmon_stats->hist_tx[9] = 3996782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 3997782bc00aSJakub Kicinski 3998782bc00aSJakub Kicinski *ranges = bnxt_rmon_ranges; 3999782bc00aSJakub Kicinski } 4000782bc00aSJakub Kicinski 4001eb513658SMichael Chan void bnxt_ethtool_free(struct bnxt *bp) 4002eb513658SMichael Chan { 4003eb513658SMichael Chan kfree(bp->test_info); 4004eb513658SMichael Chan bp->test_info = NULL; 4005eb513658SMichael Chan } 4006eb513658SMichael Chan 4007c0c050c5SMichael Chan const struct ethtool_ops bnxt_ethtool_ops = { 4008f704d243SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 4009f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES | 4010f704d243SJakub Kicinski ETHTOOL_COALESCE_USECS_IRQ | 4011f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 4012f704d243SJakub Kicinski ETHTOOL_COALESCE_STATS_BLOCK_USECS | 40133fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 40143fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_CQE, 401500c04a92SMichael Chan .get_link_ksettings = bnxt_get_link_ksettings, 401600c04a92SMichael Chan .set_link_ksettings = bnxt_set_link_ksettings, 4017c9ca5c3aSJakub Kicinski .get_fec_stats = bnxt_get_fec_stats, 40188b277589SMichael Chan .get_fecparam = bnxt_get_fecparam, 4019ccd6a9dcSMichael Chan .set_fecparam = bnxt_set_fecparam, 4020423cffcfSJakub Kicinski .get_pause_stats = bnxt_get_pause_stats, 4021c0c050c5SMichael Chan .get_pauseparam = bnxt_get_pauseparam, 4022c0c050c5SMichael Chan .set_pauseparam = bnxt_set_pauseparam, 4023c0c050c5SMichael Chan .get_drvinfo = bnxt_get_drvinfo, 4024b5d600b0SVasundhara Volam .get_regs_len = bnxt_get_regs_len, 4025b5d600b0SVasundhara Volam .get_regs = bnxt_get_regs, 40268e202366SMichael Chan .get_wol = bnxt_get_wol, 40275282db6cSMichael Chan .set_wol = bnxt_set_wol, 4028c0c050c5SMichael Chan .get_coalesce = bnxt_get_coalesce, 4029c0c050c5SMichael Chan .set_coalesce = bnxt_set_coalesce, 4030c0c050c5SMichael Chan .get_msglevel = bnxt_get_msglevel, 4031c0c050c5SMichael Chan .set_msglevel = bnxt_set_msglevel, 4032c0c050c5SMichael Chan .get_sset_count = bnxt_get_sset_count, 4033c0c050c5SMichael Chan .get_strings = bnxt_get_strings, 4034c0c050c5SMichael Chan .get_ethtool_stats = bnxt_get_ethtool_stats, 4035c0c050c5SMichael Chan .set_ringparam = bnxt_set_ringparam, 4036c0c050c5SMichael Chan .get_ringparam = bnxt_get_ringparam, 4037c0c050c5SMichael Chan .get_channels = bnxt_get_channels, 4038c0c050c5SMichael Chan .set_channels = bnxt_set_channels, 4039c0c050c5SMichael Chan .get_rxnfc = bnxt_get_rxnfc, 4040a011952aSMichael Chan .set_rxnfc = bnxt_set_rxnfc, 4041c0c050c5SMichael Chan .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 4042c0c050c5SMichael Chan .get_rxfh_key_size = bnxt_get_rxfh_key_size, 4043c0c050c5SMichael Chan .get_rxfh = bnxt_get_rxfh, 4044bd3191b5SMichael Chan .set_rxfh = bnxt_set_rxfh, 4045c0c050c5SMichael Chan .flash_device = bnxt_flash_device, 4046c0c050c5SMichael Chan .get_eeprom_len = bnxt_get_eeprom_len, 4047c0c050c5SMichael Chan .get_eeprom = bnxt_get_eeprom, 4048c0c050c5SMichael Chan .set_eeprom = bnxt_set_eeprom, 4049c0c050c5SMichael Chan .get_link = bnxt_get_link, 405072b34f04SMichael Chan .get_eee = bnxt_get_eee, 405172b34f04SMichael Chan .set_eee = bnxt_set_eee, 405242ee18feSAjit Khaparde .get_module_info = bnxt_get_module_info, 405342ee18feSAjit Khaparde .get_module_eeprom = bnxt_get_module_eeprom, 40545ad2cbeeSMichael Chan .nway_reset = bnxt_nway_reset, 40555ad2cbeeSMichael Chan .set_phys_id = bnxt_set_phys_id, 4056eb513658SMichael Chan .self_test = bnxt_self_test, 4057118612d5SMichael Chan .get_ts_info = bnxt_get_ts_info, 405849f7972fSVasundhara Volam .reset = bnxt_reset, 40590b0eacf3SVasundhara Volam .set_dump = bnxt_set_dump, 40606c5657d0SVasundhara Volam .get_dump_flag = bnxt_get_dump_flag, 40616c5657d0SVasundhara Volam .get_dump_data = bnxt_get_dump_data, 4062782bc00aSJakub Kicinski .get_eth_phy_stats = bnxt_get_eth_phy_stats, 4063782bc00aSJakub Kicinski .get_eth_mac_stats = bnxt_get_eth_mac_stats, 4064782bc00aSJakub Kicinski .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 4065782bc00aSJakub Kicinski .get_rmon_stats = bnxt_get_rmon_stats, 4066c0c050c5SMichael Chan }; 4067