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> 148b277589SMichael Chan #include <linux/linkmode.h> 15c0c050c5SMichael Chan #include <linux/interrupt.h> 16c0c050c5SMichael Chan #include <linux/pci.h> 17c0c050c5SMichael Chan #include <linux/etherdevice.h> 18c0c050c5SMichael Chan #include <linux/crc32.h> 19c0c050c5SMichael Chan #include <linux/firmware.h> 206c5657d0SVasundhara Volam #include <linux/utsname.h> 216c5657d0SVasundhara Volam #include <linux/time.h> 22118612d5SMichael Chan #include <linux/ptp_clock_kernel.h> 23118612d5SMichael Chan #include <linux/net_tstamp.h> 24118612d5SMichael Chan #include <linux/timecounter.h> 25c0c050c5SMichael Chan #include "bnxt_hsi.h" 26c0c050c5SMichael Chan #include "bnxt.h" 273c8c20dbSEdwin Peer #include "bnxt_hwrm.h" 28f7dc1ea6SMichael Chan #include "bnxt_xdp.h" 29118612d5SMichael Chan #include "bnxt_ptp.h" 30c0c050c5SMichael Chan #include "bnxt_ethtool.h" 31c0c050c5SMichael Chan #include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ 32c0c050c5SMichael Chan #include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ 336c5657d0SVasundhara Volam #include "bnxt_coredump.h" 34c0c050c5SMichael Chan 35c0c050c5SMichael Chan static u32 bnxt_get_msglevel(struct net_device *dev) 36c0c050c5SMichael Chan { 37c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 38c0c050c5SMichael Chan 39c0c050c5SMichael Chan return bp->msg_enable; 40c0c050c5SMichael Chan } 41c0c050c5SMichael Chan 42c0c050c5SMichael Chan static void bnxt_set_msglevel(struct net_device *dev, u32 value) 43c0c050c5SMichael Chan { 44c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 45c0c050c5SMichael Chan 46c0c050c5SMichael Chan bp->msg_enable = value; 47c0c050c5SMichael Chan } 48c0c050c5SMichael Chan 49c0c050c5SMichael Chan static int bnxt_get_coalesce(struct net_device *dev, 50f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 51f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 52f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 53c0c050c5SMichael Chan { 54c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 5518775aa8SMichael Chan struct bnxt_coal *hw_coal; 5618775aa8SMichael Chan u16 mult; 57c0c050c5SMichael Chan 58c0c050c5SMichael Chan memset(coal, 0, sizeof(*coal)); 59c0c050c5SMichael Chan 606a8788f2SAndy Gospodarek coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; 616a8788f2SAndy Gospodarek 6218775aa8SMichael Chan hw_coal = &bp->rx_coal; 6318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 6418775aa8SMichael Chan coal->rx_coalesce_usecs = hw_coal->coal_ticks; 6518775aa8SMichael Chan coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; 6618775aa8SMichael Chan coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 6718775aa8SMichael Chan coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 683fcbdbd5SMichael Chan if (hw_coal->flags & 693fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 703fcbdbd5SMichael Chan kernel_coal->use_cqe_mode_rx = true; 71c0c050c5SMichael Chan 7218775aa8SMichael Chan hw_coal = &bp->tx_coal; 7318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 7418775aa8SMichael Chan coal->tx_coalesce_usecs = hw_coal->coal_ticks; 7518775aa8SMichael Chan coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; 7618775aa8SMichael Chan coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 7718775aa8SMichael Chan coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 783fcbdbd5SMichael Chan if (hw_coal->flags & 793fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 803fcbdbd5SMichael Chan kernel_coal->use_cqe_mode_tx = true; 81dfc9c94aSMichael Chan 8251f30785SMichael Chan coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; 8351f30785SMichael Chan 84c0c050c5SMichael Chan return 0; 85c0c050c5SMichael Chan } 86c0c050c5SMichael Chan 87c0c050c5SMichael Chan static int bnxt_set_coalesce(struct net_device *dev, 88f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 89f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 90f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 91c0c050c5SMichael Chan { 92c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 9351f30785SMichael Chan bool update_stats = false; 9418775aa8SMichael Chan struct bnxt_coal *hw_coal; 95c0c050c5SMichael Chan int rc = 0; 9618775aa8SMichael Chan u16 mult; 97c0c050c5SMichael Chan 986a8788f2SAndy Gospodarek if (coal->use_adaptive_rx_coalesce) { 996a8788f2SAndy Gospodarek bp->flags |= BNXT_FLAG_DIM; 1006a8788f2SAndy Gospodarek } else { 1016a8788f2SAndy Gospodarek if (bp->flags & BNXT_FLAG_DIM) { 1026a8788f2SAndy Gospodarek bp->flags &= ~(BNXT_FLAG_DIM); 1036a8788f2SAndy Gospodarek goto reset_coalesce; 1046a8788f2SAndy Gospodarek } 1056a8788f2SAndy Gospodarek } 1066a8788f2SAndy Gospodarek 1073fcbdbd5SMichael Chan if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && 1083fcbdbd5SMichael Chan !(bp->coal_cap.cmpl_params & 1093fcbdbd5SMichael Chan RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) 1103fcbdbd5SMichael Chan return -EOPNOTSUPP; 1113fcbdbd5SMichael Chan 11218775aa8SMichael Chan hw_coal = &bp->rx_coal; 11318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 11418775aa8SMichael Chan hw_coal->coal_ticks = coal->rx_coalesce_usecs; 11518775aa8SMichael Chan hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; 11618775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; 11718775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; 1183fcbdbd5SMichael Chan hw_coal->flags &= 1193fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1203fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_rx) 1213fcbdbd5SMichael Chan hw_coal->flags |= 1223fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 123c0c050c5SMichael Chan 124de4a10efSAndy Gospodarek hw_coal = &bp->tx_coal; 12518775aa8SMichael Chan mult = hw_coal->bufs_per_record; 12618775aa8SMichael Chan hw_coal->coal_ticks = coal->tx_coalesce_usecs; 12718775aa8SMichael Chan hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; 12818775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; 12918775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; 1303fcbdbd5SMichael Chan hw_coal->flags &= 1313fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1323fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_tx) 1333fcbdbd5SMichael Chan hw_coal->flags |= 1343fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 135dfc9c94aSMichael Chan 13651f30785SMichael Chan if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { 13751f30785SMichael Chan u32 stats_ticks = coal->stats_block_coalesce_usecs; 13851f30785SMichael Chan 139adcc331eSMichael Chan /* Allow 0, which means disable. */ 140adcc331eSMichael Chan if (stats_ticks) 14151f30785SMichael Chan stats_ticks = clamp_t(u32, stats_ticks, 14251f30785SMichael Chan BNXT_MIN_STATS_COAL_TICKS, 14351f30785SMichael Chan BNXT_MAX_STATS_COAL_TICKS); 14451f30785SMichael Chan stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); 14551f30785SMichael Chan bp->stats_coal_ticks = stats_ticks; 146e795892eSMichael Chan if (bp->stats_coal_ticks) 147e795892eSMichael Chan bp->current_interval = 148e795892eSMichael Chan bp->stats_coal_ticks * HZ / 1000000; 149e795892eSMichael Chan else 150e795892eSMichael Chan bp->current_interval = BNXT_TIMER_INTERVAL; 15151f30785SMichael Chan update_stats = true; 15251f30785SMichael Chan } 15351f30785SMichael Chan 1546a8788f2SAndy Gospodarek reset_coalesce: 15551f30785SMichael Chan if (netif_running(dev)) { 15651f30785SMichael Chan if (update_stats) { 15751f30785SMichael Chan rc = bnxt_close_nic(bp, true, false); 15851f30785SMichael Chan if (!rc) 15951f30785SMichael Chan rc = bnxt_open_nic(bp, true, false); 16051f30785SMichael Chan } else { 161c0c050c5SMichael Chan rc = bnxt_hwrm_set_coal(bp); 16251f30785SMichael Chan } 16351f30785SMichael Chan } 164c0c050c5SMichael Chan 165c0c050c5SMichael Chan return rc; 166c0c050c5SMichael Chan } 167c0c050c5SMichael Chan 1683316d509SMichael Chan static const char * const bnxt_ring_rx_stats_str[] = { 169ee79566eSMichael Chan "rx_ucast_packets", 170ee79566eSMichael Chan "rx_mcast_packets", 171ee79566eSMichael Chan "rx_bcast_packets", 172ee79566eSMichael Chan "rx_discards", 173bfc6e5fbSMichael Chan "rx_errors", 174ee79566eSMichael Chan "rx_ucast_bytes", 175ee79566eSMichael Chan "rx_mcast_bytes", 176ee79566eSMichael Chan "rx_bcast_bytes", 1773316d509SMichael Chan }; 1783316d509SMichael Chan 1793316d509SMichael Chan static const char * const bnxt_ring_tx_stats_str[] = { 180ee79566eSMichael Chan "tx_ucast_packets", 181ee79566eSMichael Chan "tx_mcast_packets", 182ee79566eSMichael Chan "tx_bcast_packets", 183bfc6e5fbSMichael Chan "tx_errors", 184ee79566eSMichael Chan "tx_discards", 185ee79566eSMichael Chan "tx_ucast_bytes", 186ee79566eSMichael Chan "tx_mcast_bytes", 187ee79566eSMichael Chan "tx_bcast_bytes", 188ee79566eSMichael Chan }; 189ee79566eSMichael Chan 190ee79566eSMichael Chan static const char * const bnxt_ring_tpa_stats_str[] = { 191ee79566eSMichael Chan "tpa_packets", 192ee79566eSMichael Chan "tpa_bytes", 193ee79566eSMichael Chan "tpa_events", 194ee79566eSMichael Chan "tpa_aborts", 195ee79566eSMichael Chan }; 196ee79566eSMichael Chan 19778e7b866SMichael Chan static const char * const bnxt_ring_tpa2_stats_str[] = { 19878e7b866SMichael Chan "rx_tpa_eligible_pkt", 19978e7b866SMichael Chan "rx_tpa_eligible_bytes", 20078e7b866SMichael Chan "rx_tpa_pkt", 20178e7b866SMichael Chan "rx_tpa_bytes", 20278e7b866SMichael Chan "rx_tpa_errors", 2039d6b648cSMichael Chan "rx_tpa_events", 20478e7b866SMichael Chan }; 20578e7b866SMichael Chan 2069d8b5f05SMichael Chan static const char * const bnxt_rx_sw_stats_str[] = { 207ee79566eSMichael Chan "rx_l4_csum_errors", 2088a27d4b9SMichael Chan "rx_resets", 20919b3751fSMichael Chan "rx_buf_errors", 2109d8b5f05SMichael Chan }; 2119d8b5f05SMichael Chan 2129d8b5f05SMichael Chan static const char * const bnxt_cmn_sw_stats_str[] = { 213ee79566eSMichael Chan "missed_irqs", 214ee79566eSMichael Chan }; 215c0c050c5SMichael Chan 2168ddc9aaaSMichael Chan #define BNXT_RX_STATS_ENTRY(counter) \ 2178ddc9aaaSMichael Chan { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } 2188ddc9aaaSMichael Chan 2198ddc9aaaSMichael Chan #define BNXT_TX_STATS_ENTRY(counter) \ 2208ddc9aaaSMichael Chan { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } 2218ddc9aaaSMichael Chan 22200db3cbaSVasundhara Volam #define BNXT_RX_STATS_EXT_ENTRY(counter) \ 22300db3cbaSVasundhara Volam { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } 22400db3cbaSVasundhara Volam 22536e53349SMichael Chan #define BNXT_TX_STATS_EXT_ENTRY(counter) \ 22636e53349SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } 22736e53349SMichael Chan 22836e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ 22936e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ 23036e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) 23136e53349SMichael Chan 23236e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ 23336e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ 23436e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) 23536e53349SMichael Chan 23636e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRIES \ 23736e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ 23836e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ 23936e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ 24036e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ 24136e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ 24236e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ 24336e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ 24436e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(7) 24536e53349SMichael Chan 24636e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRIES \ 24736e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ 24836e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ 24936e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ 25036e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ 25136e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ 25236e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ 25336e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ 25436e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(7) 25536e53349SMichael Chan 25636e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ 25736e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ 25836e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) 25936e53349SMichael Chan 26036e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ 26136e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ 26236e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) 26336e53349SMichael Chan 26436e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRIES \ 26536e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(0), \ 26636e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(1), \ 26736e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(2), \ 26836e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(3), \ 26936e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(4), \ 27036e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(5), \ 27136e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(6), \ 27236e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(7) \ 27336e53349SMichael Chan 27436e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRIES \ 27536e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(0), \ 27636e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(1), \ 27736e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(2), \ 27836e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(3), \ 27936e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(4), \ 28036e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(5), \ 28136e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(6), \ 28236e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(7) \ 28336e53349SMichael Chan 2842792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ 2852792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ 2862792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) 2872792b5b9SMichael Chan 2882792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ 2892792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ 2902792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ 2912792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ 2922792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ 2932792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ 2942792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ 2952792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ 2962792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) 2972792b5b9SMichael Chan 298e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ 299e37fed79SMichael Chan { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ 300e37fed79SMichael Chan __stringify(counter##_pri##n) } 301e37fed79SMichael Chan 302e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ 303e37fed79SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ 304e37fed79SMichael Chan __stringify(counter##_pri##n) } 305e37fed79SMichael Chan 306e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRIES(counter) \ 307e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ 308e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ 309e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ 310e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ 311e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ 312e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ 313e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ 314e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 7) 315e37fed79SMichael Chan 316e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRIES(counter) \ 317e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ 318e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ 319e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ 320e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ 321e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ 322e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ 323e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ 324e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 7) 325e37fed79SMichael Chan 32620c1d28eSVasundhara Volam enum { 32720c1d28eSVasundhara Volam RX_TOTAL_DISCARDS, 32820c1d28eSVasundhara Volam TX_TOTAL_DISCARDS, 32940bedf7cSJakub Kicinski RX_NETPOLL_DISCARDS, 33020c1d28eSVasundhara Volam }; 33120c1d28eSVasundhara Volam 33220c1d28eSVasundhara Volam static struct { 33320c1d28eSVasundhara Volam u64 counter; 33420c1d28eSVasundhara Volam char string[ETH_GSTRING_LEN]; 33520c1d28eSVasundhara Volam } bnxt_sw_func_stats[] = { 33620c1d28eSVasundhara Volam {0, "rx_total_discard_pkts"}, 33720c1d28eSVasundhara Volam {0, "tx_total_discard_pkts"}, 33840bedf7cSJakub Kicinski {0, "rx_total_netpoll_discards"}, 33920c1d28eSVasundhara Volam }; 34020c1d28eSVasundhara Volam 3413316d509SMichael Chan #define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) 3423316d509SMichael Chan #define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) 3433316d509SMichael Chan #define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) 3443316d509SMichael Chan #define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) 3453316d509SMichael Chan 3468ddc9aaaSMichael Chan static const struct { 3478ddc9aaaSMichael Chan long offset; 3488ddc9aaaSMichael Chan char string[ETH_GSTRING_LEN]; 3498ddc9aaaSMichael Chan } bnxt_port_stats_arr[] = { 3508ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_64b_frames), 3518ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), 3528ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), 3538ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), 3548ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), 3556fc92c33SMichael Chan BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), 3568ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), 3578ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), 3588ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), 3598ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), 3608ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), 3618ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_total_frames), 3628ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ucast_frames), 3638ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mcast_frames), 3648ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bcast_frames), 3658ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), 3668ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ctrl_frames), 3678ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pause_frames), 3688ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_frames), 3698ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_align_err_frames), 3708ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), 3718ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_jbr_frames), 3728ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), 3738ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_tagged_frames), 3748ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), 3758ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_frames), 376c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), 377c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), 378c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), 379c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), 380c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), 381c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), 382c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), 383c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), 3848ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_undrsz_frames), 3858ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), 3868ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), 3878ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bytes), 3888ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_bytes), 3898ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_frames), 390699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_discard), 391699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_err), 3928ddc9aaaSMichael Chan 3938ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_64b_frames), 3948ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), 3958ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), 3968ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), 3978ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), 3986fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), 3998ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), 4006fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), 4018ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), 4028ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), 4038ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), 4048ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_frames), 4058ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_frames), 4068ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_ucast_frames), 4078ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_mcast_frames), 4088ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bcast_frames), 4098ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pause_frames), 4108ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_frames), 4118ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_jabber_frames), 4128ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), 4138ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_err), 4148ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fifo_underruns), 415c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), 416c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), 417c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), 418c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), 419c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), 420c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), 421c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), 422c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), 4238ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), 4248ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), 4258ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_collisions), 4268ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bytes), 427699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_xthol_frames), 428699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_discard), 429699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_error), 4308ddc9aaaSMichael Chan }; 4318ddc9aaaSMichael Chan 43200db3cbaSVasundhara Volam static const struct { 43300db3cbaSVasundhara Volam long offset; 43400db3cbaSVasundhara Volam char string[ETH_GSTRING_LEN]; 43500db3cbaSVasundhara Volam } bnxt_port_stats_ext_arr[] = { 43600db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(link_down_events), 43700db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), 43800db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), 43900db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), 44000db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), 44136e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRIES, 44236e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRIES, 4434a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bits), 4444a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), 4454a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), 4464a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), 4472792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, 44821e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), 44921e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), 45036e53349SMichael Chan }; 45136e53349SMichael Chan 45236e53349SMichael Chan static const struct { 45336e53349SMichael Chan long offset; 45436e53349SMichael Chan char string[ETH_GSTRING_LEN]; 45536e53349SMichael Chan } bnxt_tx_port_stats_ext_arr[] = { 45636e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRIES, 45736e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRIES, 45800db3cbaSVasundhara Volam }; 45900db3cbaSVasundhara Volam 460e37fed79SMichael Chan static const struct { 461e37fed79SMichael Chan long base_off; 462e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 463e37fed79SMichael Chan } bnxt_rx_bytes_pri_arr[] = { 464e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), 465e37fed79SMichael Chan }; 466e37fed79SMichael Chan 467e37fed79SMichael Chan static const struct { 468e37fed79SMichael Chan long base_off; 469e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 470e37fed79SMichael Chan } bnxt_rx_pkts_pri_arr[] = { 471e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_packets), 472e37fed79SMichael Chan }; 473e37fed79SMichael Chan 474e37fed79SMichael Chan static const struct { 475e37fed79SMichael Chan long base_off; 476e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 477e37fed79SMichael Chan } bnxt_tx_bytes_pri_arr[] = { 478e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), 479e37fed79SMichael Chan }; 480e37fed79SMichael Chan 481e37fed79SMichael Chan static const struct { 482e37fed79SMichael Chan long base_off; 483e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 484e37fed79SMichael Chan } bnxt_tx_pkts_pri_arr[] = { 485e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_packets), 486e37fed79SMichael Chan }; 487e37fed79SMichael Chan 48820c1d28eSVasundhara Volam #define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats) 4898ddc9aaaSMichael Chan #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) 490e37fed79SMichael Chan #define BNXT_NUM_STATS_PRI \ 491e37fed79SMichael Chan (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ 492e37fed79SMichael Chan ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ 493e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ 494e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) 4958ddc9aaaSMichael Chan 49678e7b866SMichael Chan static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) 49778e7b866SMichael Chan { 49878e7b866SMichael Chan if (BNXT_SUPPORTS_TPA(bp)) { 4999d6b648cSMichael Chan if (bp->max_tpa_v2) { 5009d6b648cSMichael Chan if (BNXT_CHIP_P5_THOR(bp)) 5019d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5; 5029d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5_SR2; 5039d6b648cSMichael Chan } 5049d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS; 50578e7b866SMichael Chan } 50678e7b866SMichael Chan return 0; 50778e7b866SMichael Chan } 50878e7b866SMichael Chan 509ee79566eSMichael Chan static int bnxt_get_num_ring_stats(struct bnxt *bp) 510ee79566eSMichael Chan { 5113316d509SMichael Chan int rx, tx, cmn; 512ee79566eSMichael Chan 5133316d509SMichael Chan rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + 51478e7b866SMichael Chan bnxt_get_num_tpa_ring_stats(bp); 5153316d509SMichael Chan tx = NUM_RING_TX_HW_STATS; 5163316d509SMichael Chan cmn = NUM_RING_CMN_SW_STATS; 517125592fbSRajesh Ravi return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + 518125592fbSRajesh Ravi cmn * bp->cp_nr_rings; 519ee79566eSMichael Chan } 520ee79566eSMichael Chan 5215c8227d0SMichael Chan static int bnxt_get_num_stats(struct bnxt *bp) 522c0c050c5SMichael Chan { 523ee79566eSMichael Chan int num_stats = bnxt_get_num_ring_stats(bp); 5248ddc9aaaSMichael Chan 52520c1d28eSVasundhara Volam num_stats += BNXT_NUM_SW_FUNC_STATS; 52620c1d28eSVasundhara Volam 5278ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) 5288ddc9aaaSMichael Chan num_stats += BNXT_NUM_PORT_STATS; 5298ddc9aaaSMichael Chan 530e37fed79SMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 53136e53349SMichael Chan num_stats += bp->fw_rx_stats_ext_size + 53236e53349SMichael Chan bp->fw_tx_stats_ext_size; 533e37fed79SMichael Chan if (bp->pri2cos_valid) 534e37fed79SMichael Chan num_stats += BNXT_NUM_STATS_PRI; 535e37fed79SMichael Chan } 53600db3cbaSVasundhara Volam 5378ddc9aaaSMichael Chan return num_stats; 5388ddc9aaaSMichael Chan } 5395c8227d0SMichael Chan 5405c8227d0SMichael Chan static int bnxt_get_sset_count(struct net_device *dev, int sset) 5415c8227d0SMichael Chan { 5425c8227d0SMichael Chan struct bnxt *bp = netdev_priv(dev); 5435c8227d0SMichael Chan 5445c8227d0SMichael Chan switch (sset) { 5455c8227d0SMichael Chan case ETH_SS_STATS: 5465c8227d0SMichael Chan return bnxt_get_num_stats(bp); 547eb513658SMichael Chan case ETH_SS_TEST: 548eb513658SMichael Chan if (!bp->num_tests) 549eb513658SMichael Chan return -EOPNOTSUPP; 550eb513658SMichael Chan return bp->num_tests; 551c0c050c5SMichael Chan default: 552c0c050c5SMichael Chan return -EOPNOTSUPP; 553c0c050c5SMichael Chan } 554c0c050c5SMichael Chan } 555c0c050c5SMichael Chan 556125592fbSRajesh Ravi static bool is_rx_ring(struct bnxt *bp, int ring_num) 557125592fbSRajesh Ravi { 558125592fbSRajesh Ravi return ring_num < bp->rx_nr_rings; 559125592fbSRajesh Ravi } 560125592fbSRajesh Ravi 561125592fbSRajesh Ravi static bool is_tx_ring(struct bnxt *bp, int ring_num) 562125592fbSRajesh Ravi { 563125592fbSRajesh Ravi int tx_base = 0; 564125592fbSRajesh Ravi 565125592fbSRajesh Ravi if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) 566125592fbSRajesh Ravi tx_base = bp->rx_nr_rings; 567125592fbSRajesh Ravi 568125592fbSRajesh Ravi if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) 569125592fbSRajesh Ravi return true; 570125592fbSRajesh Ravi return false; 571125592fbSRajesh Ravi } 572125592fbSRajesh Ravi 573c0c050c5SMichael Chan static void bnxt_get_ethtool_stats(struct net_device *dev, 574c0c050c5SMichael Chan struct ethtool_stats *stats, u64 *buf) 575c0c050c5SMichael Chan { 576c0c050c5SMichael Chan u32 i, j = 0; 577c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 578125592fbSRajesh Ravi u32 tpa_stats; 579c0c050c5SMichael Chan 580fd3ab1c7SMichael Chan if (!bp->bnapi) { 581ee79566eSMichael Chan j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS; 582fd3ab1c7SMichael Chan goto skip_ring_stats; 583fd3ab1c7SMichael Chan } 584c0c050c5SMichael Chan 58520c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) 58620c1d28eSVasundhara Volam bnxt_sw_func_stats[i].counter = 0; 58720c1d28eSVasundhara Volam 588125592fbSRajesh Ravi tpa_stats = bnxt_get_num_tpa_ring_stats(bp); 589c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 590c0c050c5SMichael Chan struct bnxt_napi *bnapi = bp->bnapi[i]; 591c0c050c5SMichael Chan struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; 592a0c30621SMichael Chan u64 *sw_stats = cpr->stats.sw_stats; 5939d8b5f05SMichael Chan u64 *sw; 594c0c050c5SMichael Chan int k; 595c0c050c5SMichael Chan 596125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 597125592fbSRajesh Ravi for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) 598a0c30621SMichael Chan buf[j] = sw_stats[k]; 599125592fbSRajesh Ravi } 600125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 601125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS; 602125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 603125592fbSRajesh Ravi j++, k++) 604a0c30621SMichael Chan buf[j] = sw_stats[k]; 605125592fbSRajesh Ravi } 606125592fbSRajesh Ravi if (!tpa_stats || !is_rx_ring(bp, i)) 607125592fbSRajesh Ravi goto skip_tpa_ring_stats; 608125592fbSRajesh Ravi 609125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 610125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + 611125592fbSRajesh Ravi tpa_stats; j++, k++) 612a0c30621SMichael Chan buf[j] = sw_stats[k]; 6139d8b5f05SMichael Chan 614125592fbSRajesh Ravi skip_tpa_ring_stats: 6159d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.rx; 616125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 6173316d509SMichael Chan for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) 6189d8b5f05SMichael Chan buf[j] = sw[k]; 619125592fbSRajesh Ravi } 6209d8b5f05SMichael Chan 6219d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.cmn; 6223316d509SMichael Chan for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) 6239d8b5f05SMichael Chan buf[j] = sw[k]; 62420c1d28eSVasundhara Volam 62520c1d28eSVasundhara Volam bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += 626a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts); 62720c1d28eSVasundhara Volam bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter += 628a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts); 62940bedf7cSJakub Kicinski bnxt_sw_func_stats[RX_NETPOLL_DISCARDS].counter += 63040bedf7cSJakub Kicinski cpr->sw_stats.rx.rx_netpoll_discards; 631c0c050c5SMichael Chan } 63220c1d28eSVasundhara Volam 63320c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++) 63420c1d28eSVasundhara Volam buf[j] = bnxt_sw_func_stats[i].counter; 63520c1d28eSVasundhara Volam 636fd3ab1c7SMichael Chan skip_ring_stats: 6378ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 638a0c30621SMichael Chan u64 *port_stats = bp->port_stats.sw_stats; 6398ddc9aaaSMichael Chan 640a0c30621SMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) 641a0c30621SMichael Chan buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); 6428ddc9aaaSMichael Chan } 64300db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 644a0c30621SMichael Chan u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; 645a0c30621SMichael Chan u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; 64600db3cbaSVasundhara Volam 64736e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { 648a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + 649a0c30621SMichael Chan bnxt_port_stats_ext_arr[i].offset); 65000db3cbaSVasundhara Volam } 65136e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { 652a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + 653a0c30621SMichael Chan bnxt_tx_port_stats_ext_arr[i].offset); 65436e53349SMichael Chan } 655e37fed79SMichael Chan if (bp->pri2cos_valid) { 656e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 657e37fed79SMichael Chan long n = bnxt_rx_bytes_pri_arr[i].base_off + 658a24ec322SMichael Chan bp->pri2cos_idx[i]; 659e37fed79SMichael Chan 660a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 661e37fed79SMichael Chan } 662e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 663e37fed79SMichael Chan long n = bnxt_rx_pkts_pri_arr[i].base_off + 664a24ec322SMichael Chan bp->pri2cos_idx[i]; 665e37fed79SMichael Chan 666a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 667e37fed79SMichael Chan } 668e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 669e37fed79SMichael Chan long n = bnxt_tx_bytes_pri_arr[i].base_off + 670a24ec322SMichael Chan bp->pri2cos_idx[i]; 671e37fed79SMichael Chan 672a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 673e37fed79SMichael Chan } 674e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 675e37fed79SMichael Chan long n = bnxt_tx_pkts_pri_arr[i].base_off + 676a24ec322SMichael Chan bp->pri2cos_idx[i]; 677e37fed79SMichael Chan 678a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 679e37fed79SMichael Chan } 680e37fed79SMichael Chan } 68100db3cbaSVasundhara Volam } 682c0c050c5SMichael Chan } 683c0c050c5SMichael Chan 684c0c050c5SMichael Chan static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 685c0c050c5SMichael Chan { 686c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 68778e7b866SMichael Chan static const char * const *str; 688ee79566eSMichael Chan u32 i, j, num_str; 689c0c050c5SMichael Chan 690c0c050c5SMichael Chan switch (stringset) { 691c0c050c5SMichael Chan case ETH_SS_STATS: 692c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 693125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 6943316d509SMichael Chan num_str = NUM_RING_RX_HW_STATS; 695ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 696ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 6973316d509SMichael Chan bnxt_ring_rx_stats_str[j]); 698c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 699ee79566eSMichael Chan } 700125592fbSRajesh Ravi } 701125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 7023316d509SMichael Chan num_str = NUM_RING_TX_HW_STATS; 7033316d509SMichael Chan for (j = 0; j < num_str; j++) { 7043316d509SMichael Chan sprintf(buf, "[%d]: %s", i, 7053316d509SMichael Chan bnxt_ring_tx_stats_str[j]); 7063316d509SMichael Chan buf += ETH_GSTRING_LEN; 7073316d509SMichael Chan } 708125592fbSRajesh Ravi } 7093316d509SMichael Chan num_str = bnxt_get_num_tpa_ring_stats(bp); 710125592fbSRajesh Ravi if (!num_str || !is_rx_ring(bp, i)) 711ee79566eSMichael Chan goto skip_tpa_stats; 712ee79566eSMichael Chan 7133316d509SMichael Chan if (bp->max_tpa_v2) 71478e7b866SMichael Chan str = bnxt_ring_tpa2_stats_str; 7153316d509SMichael Chan else 71678e7b866SMichael Chan str = bnxt_ring_tpa_stats_str; 7173316d509SMichael Chan 718ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 71978e7b866SMichael Chan sprintf(buf, "[%d]: %s", i, str[j]); 720c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 721ee79566eSMichael Chan } 722ee79566eSMichael Chan skip_tpa_stats: 723125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 7243316d509SMichael Chan num_str = NUM_RING_RX_SW_STATS; 725ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 726ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 7279d8b5f05SMichael Chan bnxt_rx_sw_stats_str[j]); 7289d8b5f05SMichael Chan buf += ETH_GSTRING_LEN; 7299d8b5f05SMichael Chan } 730125592fbSRajesh Ravi } 7313316d509SMichael Chan num_str = NUM_RING_CMN_SW_STATS; 7329d8b5f05SMichael Chan for (j = 0; j < num_str; j++) { 7339d8b5f05SMichael Chan sprintf(buf, "[%d]: %s", i, 7349d8b5f05SMichael Chan bnxt_cmn_sw_stats_str[j]); 735c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 736ee79566eSMichael Chan } 737c0c050c5SMichael Chan } 73820c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) { 73920c1d28eSVasundhara Volam strcpy(buf, bnxt_sw_func_stats[i].string); 74020c1d28eSVasundhara Volam buf += ETH_GSTRING_LEN; 74120c1d28eSVasundhara Volam } 74220c1d28eSVasundhara Volam 7438ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 7448ddc9aaaSMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { 7458ddc9aaaSMichael Chan strcpy(buf, bnxt_port_stats_arr[i].string); 7468ddc9aaaSMichael Chan buf += ETH_GSTRING_LEN; 7478ddc9aaaSMichael Chan } 7488ddc9aaaSMichael Chan } 74900db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 75036e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { 75100db3cbaSVasundhara Volam strcpy(buf, bnxt_port_stats_ext_arr[i].string); 75200db3cbaSVasundhara Volam buf += ETH_GSTRING_LEN; 75300db3cbaSVasundhara Volam } 75436e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { 75536e53349SMichael Chan strcpy(buf, 75636e53349SMichael Chan bnxt_tx_port_stats_ext_arr[i].string); 75736e53349SMichael Chan buf += ETH_GSTRING_LEN; 75836e53349SMichael Chan } 759e37fed79SMichael Chan if (bp->pri2cos_valid) { 760e37fed79SMichael Chan for (i = 0; i < 8; i++) { 761e37fed79SMichael Chan strcpy(buf, 762e37fed79SMichael Chan bnxt_rx_bytes_pri_arr[i].string); 763e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 764e37fed79SMichael Chan } 765e37fed79SMichael Chan for (i = 0; i < 8; i++) { 766e37fed79SMichael Chan strcpy(buf, 767e37fed79SMichael Chan bnxt_rx_pkts_pri_arr[i].string); 768e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 769e37fed79SMichael Chan } 770e37fed79SMichael Chan for (i = 0; i < 8; i++) { 771e37fed79SMichael Chan strcpy(buf, 772e37fed79SMichael Chan bnxt_tx_bytes_pri_arr[i].string); 773e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 774e37fed79SMichael Chan } 775e37fed79SMichael Chan for (i = 0; i < 8; i++) { 776e37fed79SMichael Chan strcpy(buf, 777e37fed79SMichael Chan bnxt_tx_pkts_pri_arr[i].string); 778e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 779e37fed79SMichael Chan } 780e37fed79SMichael Chan } 78100db3cbaSVasundhara Volam } 782c0c050c5SMichael Chan break; 783eb513658SMichael Chan case ETH_SS_TEST: 784eb513658SMichael Chan if (bp->num_tests) 785eb513658SMichael Chan memcpy(buf, bp->test_info->string, 786eb513658SMichael Chan bp->num_tests * ETH_GSTRING_LEN); 787eb513658SMichael Chan break; 788c0c050c5SMichael Chan default: 789c0c050c5SMichael Chan netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", 790c0c050c5SMichael Chan stringset); 791c0c050c5SMichael Chan break; 792c0c050c5SMichael Chan } 793c0c050c5SMichael Chan } 794c0c050c5SMichael Chan 795c0c050c5SMichael Chan static void bnxt_get_ringparam(struct net_device *dev, 79674624944SHao Chen struct ethtool_ringparam *ering, 79774624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 79874624944SHao Chen struct netlink_ext_ack *extack) 799c0c050c5SMichael Chan { 800c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 801c0c050c5SMichael Chan 802c1129b51SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) { 803c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA; 804c0c050c5SMichael Chan ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; 805c1129b51SMichael Chan } else { 806c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; 807c1129b51SMichael Chan ering->rx_jumbo_max_pending = 0; 808c1129b51SMichael Chan } 809c0c050c5SMichael Chan ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; 810c0c050c5SMichael Chan 811c0c050c5SMichael Chan ering->rx_pending = bp->rx_ring_size; 812c0c050c5SMichael Chan ering->rx_jumbo_pending = bp->rx_agg_ring_size; 813c0c050c5SMichael Chan ering->tx_pending = bp->tx_ring_size; 814c0c050c5SMichael Chan } 815c0c050c5SMichael Chan 816c0c050c5SMichael Chan static int bnxt_set_ringparam(struct net_device *dev, 81774624944SHao Chen struct ethtool_ringparam *ering, 81874624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 81974624944SHao Chen struct netlink_ext_ack *extack) 820c0c050c5SMichael Chan { 821c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 822c0c050c5SMichael Chan 823c0c050c5SMichael Chan if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || 824c0c050c5SMichael Chan (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || 8255bed8b07SMichael Chan (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) 826c0c050c5SMichael Chan return -EINVAL; 827c0c050c5SMichael Chan 828c0c050c5SMichael Chan if (netif_running(dev)) 829c0c050c5SMichael Chan bnxt_close_nic(bp, false, false); 830c0c050c5SMichael Chan 831c0c050c5SMichael Chan bp->rx_ring_size = ering->rx_pending; 832c0c050c5SMichael Chan bp->tx_ring_size = ering->tx_pending; 833c0c050c5SMichael Chan bnxt_set_ring_params(bp); 834c0c050c5SMichael Chan 835c0c050c5SMichael Chan if (netif_running(dev)) 836c0c050c5SMichael Chan return bnxt_open_nic(bp, false, false); 837c0c050c5SMichael Chan 838c0c050c5SMichael Chan return 0; 839c0c050c5SMichael Chan } 840c0c050c5SMichael Chan 841c0c050c5SMichael Chan static void bnxt_get_channels(struct net_device *dev, 842c0c050c5SMichael Chan struct ethtool_channels *channel) 843c0c050c5SMichael Chan { 844c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 845db4723b3SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 846c0c050c5SMichael Chan int max_rx_rings, max_tx_rings, tcs; 8474301304bSMichael Chan int max_tx_sch_inputs, tx_grps; 848db4723b3SMichael Chan 849db4723b3SMichael Chan /* Get the most up-to-date max_tx_sch_inputs. */ 850c1c2d774SPavan Chebbi if (netif_running(dev) && BNXT_NEW_RM(bp)) 851db4723b3SMichael Chan bnxt_hwrm_func_resc_qcaps(bp, false); 852db4723b3SMichael Chan max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; 853c0c050c5SMichael Chan 8546e6c5a57SMichael Chan bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); 855db4723b3SMichael Chan if (max_tx_sch_inputs) 856db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 8574301304bSMichael Chan 8584301304bSMichael Chan tcs = netdev_get_num_tc(dev); 8594301304bSMichael Chan tx_grps = max(tcs, 1); 8604301304bSMichael Chan if (bp->tx_nr_rings_xdp) 8614301304bSMichael Chan tx_grps++; 8624301304bSMichael Chan max_tx_rings /= tx_grps; 863a79a5276SMichael Chan channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); 864068c9ec6SMichael Chan 86518d6e4e2SSatish Baddipadige if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { 86618d6e4e2SSatish Baddipadige max_rx_rings = 0; 86718d6e4e2SSatish Baddipadige max_tx_rings = 0; 86818d6e4e2SSatish Baddipadige } 869db4723b3SMichael Chan if (max_tx_sch_inputs) 870db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 87118d6e4e2SSatish Baddipadige 872c0c050c5SMichael Chan if (tcs > 1) 873c0c050c5SMichael Chan max_tx_rings /= tcs; 874c0c050c5SMichael Chan 875c0c050c5SMichael Chan channel->max_rx = max_rx_rings; 876c0c050c5SMichael Chan channel->max_tx = max_tx_rings; 877c0c050c5SMichael Chan channel->max_other = 0; 878068c9ec6SMichael Chan if (bp->flags & BNXT_FLAG_SHARED_RINGS) { 879068c9ec6SMichael Chan channel->combined_count = bp->rx_nr_rings; 88076595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp)) 88176595193SPrashant Sreedharan channel->combined_count--; 882068c9ec6SMichael Chan } else { 88376595193SPrashant Sreedharan if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { 884c0c050c5SMichael Chan channel->rx_count = bp->rx_nr_rings; 885c0c050c5SMichael Chan channel->tx_count = bp->tx_nr_rings_per_tc; 886c0c050c5SMichael Chan } 887068c9ec6SMichael Chan } 88876595193SPrashant Sreedharan } 889c0c050c5SMichael Chan 890c0c050c5SMichael Chan static int bnxt_set_channels(struct net_device *dev, 891c0c050c5SMichael Chan struct ethtool_channels *channel) 892c0c050c5SMichael Chan { 893c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 894d1e7925eSMichael Chan int req_tx_rings, req_rx_rings, tcs; 895068c9ec6SMichael Chan bool sh = false; 8965f449249SMichael Chan int tx_xdp = 0; 897d1e7925eSMichael Chan int rc = 0; 898c0c050c5SMichael Chan 899068c9ec6SMichael Chan if (channel->other_count) 900c0c050c5SMichael Chan return -EINVAL; 901c0c050c5SMichael Chan 902068c9ec6SMichael Chan if (!channel->combined_count && 903068c9ec6SMichael Chan (!channel->rx_count || !channel->tx_count)) 904068c9ec6SMichael Chan return -EINVAL; 905068c9ec6SMichael Chan 906068c9ec6SMichael Chan if (channel->combined_count && 907068c9ec6SMichael Chan (channel->rx_count || channel->tx_count)) 908068c9ec6SMichael Chan return -EINVAL; 909068c9ec6SMichael Chan 91076595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || 91176595193SPrashant Sreedharan channel->tx_count)) 91276595193SPrashant Sreedharan return -EINVAL; 91376595193SPrashant Sreedharan 914068c9ec6SMichael Chan if (channel->combined_count) 915068c9ec6SMichael Chan sh = true; 916068c9ec6SMichael Chan 917c0c050c5SMichael Chan tcs = netdev_get_num_tc(dev); 918c0c050c5SMichael Chan 919391be5c2SMichael Chan req_tx_rings = sh ? channel->combined_count : channel->tx_count; 920d1e7925eSMichael Chan req_rx_rings = sh ? channel->combined_count : channel->rx_count; 9215f449249SMichael Chan if (bp->tx_nr_rings_xdp) { 9225f449249SMichael Chan if (!sh) { 9235f449249SMichael Chan netdev_err(dev, "Only combined mode supported when XDP is enabled.\n"); 9245f449249SMichael Chan return -EINVAL; 9255f449249SMichael Chan } 9265f449249SMichael Chan tx_xdp = req_rx_rings; 9275f449249SMichael Chan } 92898fdbe73SMichael Chan rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); 929d1e7925eSMichael Chan if (rc) { 930d1e7925eSMichael Chan netdev_warn(dev, "Unable to allocate the requested rings\n"); 931d1e7925eSMichael Chan return rc; 932391be5c2SMichael Chan } 933391be5c2SMichael Chan 934bd3191b5SMichael Chan if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != 935bd3191b5SMichael Chan bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && 9364b70dce2SJuhee Kang netif_is_rxfh_configured(dev)) { 937bd3191b5SMichael Chan netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n"); 938bd3191b5SMichael Chan return -EINVAL; 939bd3191b5SMichael Chan } 940bd3191b5SMichael Chan 941c0c050c5SMichael Chan if (netif_running(dev)) { 942c0c050c5SMichael Chan if (BNXT_PF(bp)) { 943c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 944c0c050c5SMichael Chan * before PF unload 945c0c050c5SMichael Chan */ 946c0c050c5SMichael Chan } 947c0c050c5SMichael Chan rc = bnxt_close_nic(bp, true, false); 948c0c050c5SMichael Chan if (rc) { 949c0c050c5SMichael Chan netdev_err(bp->dev, "Set channel failure rc :%x\n", 950c0c050c5SMichael Chan rc); 951c0c050c5SMichael Chan return rc; 952c0c050c5SMichael Chan } 953c0c050c5SMichael Chan } 954c0c050c5SMichael Chan 955068c9ec6SMichael Chan if (sh) { 956068c9ec6SMichael Chan bp->flags |= BNXT_FLAG_SHARED_RINGS; 957d1e7925eSMichael Chan bp->rx_nr_rings = channel->combined_count; 958d1e7925eSMichael Chan bp->tx_nr_rings_per_tc = channel->combined_count; 959068c9ec6SMichael Chan } else { 960068c9ec6SMichael Chan bp->flags &= ~BNXT_FLAG_SHARED_RINGS; 961c0c050c5SMichael Chan bp->rx_nr_rings = channel->rx_count; 962c0c050c5SMichael Chan bp->tx_nr_rings_per_tc = channel->tx_count; 963068c9ec6SMichael Chan } 9645f449249SMichael Chan bp->tx_nr_rings_xdp = tx_xdp; 9655f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; 966c0c050c5SMichael Chan if (tcs > 1) 9675f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; 968068c9ec6SMichael Chan 969068c9ec6SMichael Chan bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : 970068c9ec6SMichael Chan bp->tx_nr_rings + bp->rx_nr_rings; 971068c9ec6SMichael Chan 9722bcfa6f6SMichael Chan /* After changing number of rx channels, update NTUPLE feature. */ 9732bcfa6f6SMichael Chan netdev_update_features(dev); 974c0c050c5SMichael Chan if (netif_running(dev)) { 975c0c050c5SMichael Chan rc = bnxt_open_nic(bp, true, false); 976c0c050c5SMichael Chan if ((!rc) && BNXT_PF(bp)) { 977c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 978c0c050c5SMichael Chan * to renable 979c0c050c5SMichael Chan */ 980c0c050c5SMichael Chan } 981d8c09f19SMichael Chan } else { 9821b3f0b75SMichael Chan rc = bnxt_reserve_rings(bp, true); 983c0c050c5SMichael Chan } 984c0c050c5SMichael Chan 985c0c050c5SMichael Chan return rc; 986c0c050c5SMichael Chan } 987c0c050c5SMichael Chan 988c0c050c5SMichael Chan #ifdef CONFIG_RFS_ACCEL 989c0c050c5SMichael Chan static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, 990c0c050c5SMichael Chan u32 *rule_locs) 991c0c050c5SMichael Chan { 992c0c050c5SMichael Chan int i, j = 0; 993c0c050c5SMichael Chan 994c0c050c5SMichael Chan cmd->data = bp->ntp_fltr_count; 995c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 996c0c050c5SMichael Chan struct hlist_head *head; 997c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 998c0c050c5SMichael Chan 999c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1000c0c050c5SMichael Chan rcu_read_lock(); 1001c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1002c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1003c0c050c5SMichael Chan break; 1004c0c050c5SMichael Chan rule_locs[j++] = fltr->sw_id; 1005c0c050c5SMichael Chan } 1006c0c050c5SMichael Chan rcu_read_unlock(); 1007c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1008c0c050c5SMichael Chan break; 1009c0c050c5SMichael Chan } 1010c0c050c5SMichael Chan cmd->rule_cnt = j; 1011c0c050c5SMichael Chan return 0; 1012c0c050c5SMichael Chan } 1013c0c050c5SMichael Chan 1014c0c050c5SMichael Chan static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1015c0c050c5SMichael Chan { 1016c0c050c5SMichael Chan struct ethtool_rx_flow_spec *fs = 1017c0c050c5SMichael Chan (struct ethtool_rx_flow_spec *)&cmd->fs; 1018c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 1019c0c050c5SMichael Chan struct flow_keys *fkeys; 1020c0c050c5SMichael Chan int i, rc = -EINVAL; 1021c0c050c5SMichael Chan 1022b721cfafSstephen hemminger if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) 1023c0c050c5SMichael Chan return rc; 1024c0c050c5SMichael Chan 1025c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 1026c0c050c5SMichael Chan struct hlist_head *head; 1027c0c050c5SMichael Chan 1028c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1029c0c050c5SMichael Chan rcu_read_lock(); 1030c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1031c0c050c5SMichael Chan if (fltr->sw_id == fs->location) 1032c0c050c5SMichael Chan goto fltr_found; 1033c0c050c5SMichael Chan } 1034c0c050c5SMichael Chan rcu_read_unlock(); 1035c0c050c5SMichael Chan } 1036c0c050c5SMichael Chan return rc; 1037c0c050c5SMichael Chan 1038c0c050c5SMichael Chan fltr_found: 1039c0c050c5SMichael Chan fkeys = &fltr->fkeys; 1040dda0e746SMichael Chan if (fkeys->basic.n_proto == htons(ETH_P_IP)) { 1041c0c050c5SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1042c0c050c5SMichael Chan fs->flow_type = TCP_V4_FLOW; 1043c0c050c5SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1044c0c050c5SMichael Chan fs->flow_type = UDP_V4_FLOW; 1045c0c050c5SMichael Chan else 1046c0c050c5SMichael Chan goto fltr_err; 1047c0c050c5SMichael Chan 1048c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; 1049c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); 1050c0c050c5SMichael Chan 1051c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; 1052c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); 1053c0c050c5SMichael Chan 1054c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; 1055c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); 1056c0c050c5SMichael Chan 1057c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; 1058c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); 1059dda0e746SMichael Chan } else { 1060dda0e746SMichael Chan int i; 1061dda0e746SMichael Chan 1062dda0e746SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1063dda0e746SMichael Chan fs->flow_type = TCP_V6_FLOW; 1064dda0e746SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1065dda0e746SMichael Chan fs->flow_type = UDP_V6_FLOW; 1066dda0e746SMichael Chan else 1067dda0e746SMichael Chan goto fltr_err; 1068dda0e746SMichael Chan 1069dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = 1070dda0e746SMichael Chan fkeys->addrs.v6addrs.src; 1071dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = 1072dda0e746SMichael Chan fkeys->addrs.v6addrs.dst; 1073dda0e746SMichael Chan for (i = 0; i < 4; i++) { 1074dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); 1075dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); 1076dda0e746SMichael Chan } 1077dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; 1078dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); 1079dda0e746SMichael Chan 1080dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; 1081dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); 1082dda0e746SMichael Chan } 1083c0c050c5SMichael Chan 1084c0c050c5SMichael Chan fs->ring_cookie = fltr->rxq; 1085c0c050c5SMichael Chan rc = 0; 1086c0c050c5SMichael Chan 1087c0c050c5SMichael Chan fltr_err: 1088c0c050c5SMichael Chan rcu_read_unlock(); 1089c0c050c5SMichael Chan 1090c0c050c5SMichael Chan return rc; 1091c0c050c5SMichael Chan } 1092a011952aSMichael Chan #endif 1093a011952aSMichael Chan 1094a011952aSMichael Chan static u64 get_ethtool_ipv4_rss(struct bnxt *bp) 1095a011952aSMichael Chan { 1096a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) 1097a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1098a011952aSMichael Chan return 0; 1099a011952aSMichael Chan } 1100a011952aSMichael Chan 1101a011952aSMichael Chan static u64 get_ethtool_ipv6_rss(struct bnxt *bp) 1102a011952aSMichael Chan { 1103a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) 1104a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1105a011952aSMichael Chan return 0; 1106a011952aSMichael Chan } 1107a011952aSMichael Chan 1108a011952aSMichael Chan static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1109a011952aSMichael Chan { 1110a011952aSMichael Chan cmd->data = 0; 1111a011952aSMichael Chan switch (cmd->flow_type) { 1112a011952aSMichael Chan case TCP_V4_FLOW: 1113a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) 1114a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1115a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1116a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1117a011952aSMichael Chan break; 1118a011952aSMichael Chan case UDP_V4_FLOW: 1119a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) 1120a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1121a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1122df561f66SGustavo A. R. Silva fallthrough; 1123a011952aSMichael Chan case SCTP_V4_FLOW: 1124a011952aSMichael Chan case AH_ESP_V4_FLOW: 1125a011952aSMichael Chan case AH_V4_FLOW: 1126a011952aSMichael Chan case ESP_V4_FLOW: 1127a011952aSMichael Chan case IPV4_FLOW: 1128a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1129a011952aSMichael Chan break; 1130a011952aSMichael Chan 1131a011952aSMichael Chan case TCP_V6_FLOW: 1132a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) 1133a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1134a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1135a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1136a011952aSMichael Chan break; 1137a011952aSMichael Chan case UDP_V6_FLOW: 1138a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) 1139a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1140a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1141df561f66SGustavo A. R. Silva fallthrough; 1142a011952aSMichael Chan case SCTP_V6_FLOW: 1143a011952aSMichael Chan case AH_ESP_V6_FLOW: 1144a011952aSMichael Chan case AH_V6_FLOW: 1145a011952aSMichael Chan case ESP_V6_FLOW: 1146a011952aSMichael Chan case IPV6_FLOW: 1147a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1148a011952aSMichael Chan break; 1149a011952aSMichael Chan } 1150a011952aSMichael Chan return 0; 1151a011952aSMichael Chan } 1152a011952aSMichael Chan 1153a011952aSMichael Chan #define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 1154a011952aSMichael Chan #define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) 1155a011952aSMichael Chan 1156a011952aSMichael Chan static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1157a011952aSMichael Chan { 1158a011952aSMichael Chan u32 rss_hash_cfg = bp->rss_hash_cfg; 1159a011952aSMichael Chan int tuple, rc = 0; 1160a011952aSMichael Chan 1161a011952aSMichael Chan if (cmd->data == RXH_4TUPLE) 1162a011952aSMichael Chan tuple = 4; 1163a011952aSMichael Chan else if (cmd->data == RXH_2TUPLE) 1164a011952aSMichael Chan tuple = 2; 1165a011952aSMichael Chan else if (!cmd->data) 1166a011952aSMichael Chan tuple = 0; 1167a011952aSMichael Chan else 1168a011952aSMichael Chan return -EINVAL; 1169a011952aSMichael Chan 1170a011952aSMichael Chan if (cmd->flow_type == TCP_V4_FLOW) { 1171a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1172a011952aSMichael Chan if (tuple == 4) 1173a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1174a011952aSMichael Chan } else if (cmd->flow_type == UDP_V4_FLOW) { 1175a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1176a011952aSMichael Chan return -EINVAL; 1177a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1178a011952aSMichael Chan if (tuple == 4) 1179a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1180a011952aSMichael Chan } else if (cmd->flow_type == TCP_V6_FLOW) { 1181a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1182a011952aSMichael Chan if (tuple == 4) 1183a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1184a011952aSMichael Chan } else if (cmd->flow_type == UDP_V6_FLOW) { 1185a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1186a011952aSMichael Chan return -EINVAL; 1187a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1188a011952aSMichael Chan if (tuple == 4) 1189a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1190a011952aSMichael Chan } else if (tuple == 4) { 1191a011952aSMichael Chan return -EINVAL; 1192a011952aSMichael Chan } 1193a011952aSMichael Chan 1194a011952aSMichael Chan switch (cmd->flow_type) { 1195a011952aSMichael Chan case TCP_V4_FLOW: 1196a011952aSMichael Chan case UDP_V4_FLOW: 1197a011952aSMichael Chan case SCTP_V4_FLOW: 1198a011952aSMichael Chan case AH_ESP_V4_FLOW: 1199a011952aSMichael Chan case AH_V4_FLOW: 1200a011952aSMichael Chan case ESP_V4_FLOW: 1201a011952aSMichael Chan case IPV4_FLOW: 1202a011952aSMichael Chan if (tuple == 2) 1203a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1204a011952aSMichael Chan else if (!tuple) 1205a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1206a011952aSMichael Chan break; 1207a011952aSMichael Chan 1208a011952aSMichael Chan case TCP_V6_FLOW: 1209a011952aSMichael Chan case UDP_V6_FLOW: 1210a011952aSMichael Chan case SCTP_V6_FLOW: 1211a011952aSMichael Chan case AH_ESP_V6_FLOW: 1212a011952aSMichael Chan case AH_V6_FLOW: 1213a011952aSMichael Chan case ESP_V6_FLOW: 1214a011952aSMichael Chan case IPV6_FLOW: 1215a011952aSMichael Chan if (tuple == 2) 1216a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1217a011952aSMichael Chan else if (!tuple) 1218a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1219a011952aSMichael Chan break; 1220a011952aSMichael Chan } 1221a011952aSMichael Chan 1222a011952aSMichael Chan if (bp->rss_hash_cfg == rss_hash_cfg) 1223a011952aSMichael Chan return 0; 1224a011952aSMichael Chan 1225a011952aSMichael Chan bp->rss_hash_cfg = rss_hash_cfg; 1226a011952aSMichael Chan if (netif_running(bp->dev)) { 1227a011952aSMichael Chan bnxt_close_nic(bp, false, false); 1228a011952aSMichael Chan rc = bnxt_open_nic(bp, false, false); 1229a011952aSMichael Chan } 1230a011952aSMichael Chan return rc; 1231a011952aSMichael Chan } 1232c0c050c5SMichael Chan 1233c0c050c5SMichael Chan static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 1234c0c050c5SMichael Chan u32 *rule_locs) 1235c0c050c5SMichael Chan { 1236c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1237c0c050c5SMichael Chan int rc = 0; 1238c0c050c5SMichael Chan 1239c0c050c5SMichael Chan switch (cmd->cmd) { 1240a011952aSMichael Chan #ifdef CONFIG_RFS_ACCEL 1241c0c050c5SMichael Chan case ETHTOOL_GRXRINGS: 1242c0c050c5SMichael Chan cmd->data = bp->rx_nr_rings; 1243c0c050c5SMichael Chan break; 1244c0c050c5SMichael Chan 1245c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLCNT: 1246c0c050c5SMichael Chan cmd->rule_cnt = bp->ntp_fltr_count; 1247c0c050c5SMichael Chan cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 1248c0c050c5SMichael Chan break; 1249c0c050c5SMichael Chan 1250c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLALL: 1251c0c050c5SMichael Chan rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 1252c0c050c5SMichael Chan break; 1253c0c050c5SMichael Chan 1254c0c050c5SMichael Chan case ETHTOOL_GRXCLSRULE: 1255c0c050c5SMichael Chan rc = bnxt_grxclsrule(bp, cmd); 1256c0c050c5SMichael Chan break; 1257a011952aSMichael Chan #endif 1258a011952aSMichael Chan 1259a011952aSMichael Chan case ETHTOOL_GRXFH: 1260a011952aSMichael Chan rc = bnxt_grxfh(bp, cmd); 1261a011952aSMichael Chan break; 1262c0c050c5SMichael Chan 1263c0c050c5SMichael Chan default: 1264c0c050c5SMichael Chan rc = -EOPNOTSUPP; 1265c0c050c5SMichael Chan break; 1266c0c050c5SMichael Chan } 1267c0c050c5SMichael Chan 1268c0c050c5SMichael Chan return rc; 1269c0c050c5SMichael Chan } 1270a011952aSMichael Chan 1271a011952aSMichael Chan static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 1272a011952aSMichael Chan { 1273a011952aSMichael Chan struct bnxt *bp = netdev_priv(dev); 1274a011952aSMichael Chan int rc; 1275a011952aSMichael Chan 1276a011952aSMichael Chan switch (cmd->cmd) { 1277a011952aSMichael Chan case ETHTOOL_SRXFH: 1278a011952aSMichael Chan rc = bnxt_srxfh(bp, cmd); 1279a011952aSMichael Chan break; 1280a011952aSMichael Chan 1281a011952aSMichael Chan default: 1282a011952aSMichael Chan rc = -EOPNOTSUPP; 1283a011952aSMichael Chan break; 1284a011952aSMichael Chan } 1285a011952aSMichael Chan return rc; 1286a011952aSMichael Chan } 1287c0c050c5SMichael Chan 1288b73c1d08SMichael Chan u32 bnxt_get_rxfh_indir_size(struct net_device *dev) 1289c0c050c5SMichael Chan { 1290b73c1d08SMichael Chan struct bnxt *bp = netdev_priv(dev); 1291b73c1d08SMichael Chan 1292b73c1d08SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 1293b73c1d08SMichael Chan return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 1294c0c050c5SMichael Chan return HW_HASH_INDEX_SIZE; 1295c0c050c5SMichael Chan } 1296c0c050c5SMichael Chan 1297c0c050c5SMichael Chan static u32 bnxt_get_rxfh_key_size(struct net_device *dev) 1298c0c050c5SMichael Chan { 1299c0c050c5SMichael Chan return HW_HASH_KEY_SIZE; 1300c0c050c5SMichael Chan } 1301c0c050c5SMichael Chan 1302c0c050c5SMichael Chan static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 1303c0c050c5SMichael Chan u8 *hfunc) 1304c0c050c5SMichael Chan { 1305c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 13067991cb9cSMichael Chan struct bnxt_vnic_info *vnic; 1307adc38ac6SMichael Chan u32 i, tbl_size; 1308c0c050c5SMichael Chan 1309c0c050c5SMichael Chan if (hfunc) 1310c0c050c5SMichael Chan *hfunc = ETH_RSS_HASH_TOP; 1311c0c050c5SMichael Chan 13127991cb9cSMichael Chan if (!bp->vnic_info) 13137991cb9cSMichael Chan return 0; 13147991cb9cSMichael Chan 13157991cb9cSMichael Chan vnic = &bp->vnic_info[0]; 1316adc38ac6SMichael Chan if (indir && bp->rss_indir_tbl) { 1317adc38ac6SMichael Chan tbl_size = bnxt_get_rxfh_indir_size(dev); 1318adc38ac6SMichael Chan for (i = 0; i < tbl_size; i++) 1319adc38ac6SMichael Chan indir[i] = bp->rss_indir_tbl[i]; 13207991cb9cSMichael Chan } 1321c0c050c5SMichael Chan 13227991cb9cSMichael Chan if (key && vnic->rss_hash_key) 1323c0c050c5SMichael Chan memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 1324c0c050c5SMichael Chan 1325c0c050c5SMichael Chan return 0; 1326c0c050c5SMichael Chan } 1327c0c050c5SMichael Chan 1328bd3191b5SMichael Chan static int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 1329bd3191b5SMichael Chan const u8 *key, const u8 hfunc) 1330bd3191b5SMichael Chan { 1331bd3191b5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1332bd3191b5SMichael Chan int rc = 0; 1333bd3191b5SMichael Chan 1334bd3191b5SMichael Chan if (hfunc && hfunc != ETH_RSS_HASH_TOP) 1335bd3191b5SMichael Chan return -EOPNOTSUPP; 1336bd3191b5SMichael Chan 1337bd3191b5SMichael Chan if (key) 1338bd3191b5SMichael Chan return -EOPNOTSUPP; 1339bd3191b5SMichael Chan 1340bd3191b5SMichael Chan if (indir) { 1341bd3191b5SMichael Chan u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 1342bd3191b5SMichael Chan 1343bd3191b5SMichael Chan for (i = 0; i < tbl_size; i++) 1344bd3191b5SMichael Chan bp->rss_indir_tbl[i] = indir[i]; 1345bd3191b5SMichael Chan pad = bp->rss_indir_tbl_entries - tbl_size; 1346bd3191b5SMichael Chan if (pad) 1347bd3191b5SMichael Chan memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 1348bd3191b5SMichael Chan } 1349bd3191b5SMichael Chan 1350bd3191b5SMichael Chan if (netif_running(bp->dev)) { 1351bd3191b5SMichael Chan bnxt_close_nic(bp, false, false); 1352bd3191b5SMichael Chan rc = bnxt_open_nic(bp, false, false); 1353bd3191b5SMichael Chan } 1354bd3191b5SMichael Chan return rc; 1355bd3191b5SMichael Chan } 1356bd3191b5SMichael Chan 1357c0c050c5SMichael Chan static void bnxt_get_drvinfo(struct net_device *dev, 1358c0c050c5SMichael Chan struct ethtool_drvinfo *info) 1359c0c050c5SMichael Chan { 1360c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1361c0c050c5SMichael Chan 1362c0c050c5SMichael Chan strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 1363431aa1ebSMichael Chan strlcpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 1364c0c050c5SMichael Chan strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 13655c8227d0SMichael Chan info->n_stats = bnxt_get_num_stats(bp); 1366eb513658SMichael Chan info->testinfo_len = bp->num_tests; 1367c0c050c5SMichael Chan /* TODO CHIMP_FW: eeprom dump details */ 1368c0c050c5SMichael Chan info->eedump_len = 0; 1369c0c050c5SMichael Chan /* TODO CHIMP FW: reg dump details */ 1370c0c050c5SMichael Chan info->regdump_len = 0; 1371c0c050c5SMichael Chan } 1372c0c050c5SMichael Chan 1373b5d600b0SVasundhara Volam static int bnxt_get_regs_len(struct net_device *dev) 1374b5d600b0SVasundhara Volam { 1375b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1376b5d600b0SVasundhara Volam int reg_len; 1377b5d600b0SVasundhara Volam 1378f0f47b2fSVasundhara Volam if (!BNXT_PF(bp)) 1379f0f47b2fSVasundhara Volam return -EOPNOTSUPP; 1380f0f47b2fSVasundhara Volam 1381b5d600b0SVasundhara Volam reg_len = BNXT_PXP_REG_LEN; 1382b5d600b0SVasundhara Volam 1383b5d600b0SVasundhara Volam if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 1384b5d600b0SVasundhara Volam reg_len += sizeof(struct pcie_ctx_hw_stats); 1385b5d600b0SVasundhara Volam 1386b5d600b0SVasundhara Volam return reg_len; 1387b5d600b0SVasundhara Volam } 1388b5d600b0SVasundhara Volam 1389b5d600b0SVasundhara Volam static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 1390b5d600b0SVasundhara Volam void *_p) 1391b5d600b0SVasundhara Volam { 1392b5d600b0SVasundhara Volam struct pcie_ctx_hw_stats *hw_pcie_stats; 1393bbf33d1dSEdwin Peer struct hwrm_pcie_qstats_input *req; 1394b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1395b5d600b0SVasundhara Volam dma_addr_t hw_pcie_stats_addr; 1396b5d600b0SVasundhara Volam int rc; 1397b5d600b0SVasundhara Volam 1398b5d600b0SVasundhara Volam regs->version = 0; 1399b5d600b0SVasundhara Volam bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 1400b5d600b0SVasundhara Volam 1401b5d600b0SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 1402b5d600b0SVasundhara Volam return; 1403b5d600b0SVasundhara Volam 1404bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) 1405b5d600b0SVasundhara Volam return; 1406b5d600b0SVasundhara Volam 1407bbf33d1dSEdwin Peer hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), 1408bbf33d1dSEdwin Peer &hw_pcie_stats_addr); 1409bbf33d1dSEdwin Peer if (!hw_pcie_stats) { 1410bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1411bbf33d1dSEdwin Peer return; 1412bbf33d1dSEdwin Peer } 1413bbf33d1dSEdwin Peer 1414b5d600b0SVasundhara Volam regs->version = 1; 1415bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold on to slice */ 1416bbf33d1dSEdwin Peer req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 1417bbf33d1dSEdwin Peer req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 1418bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 1419b5d600b0SVasundhara Volam if (!rc) { 1420b5d600b0SVasundhara Volam __le64 *src = (__le64 *)hw_pcie_stats; 1421b5d600b0SVasundhara Volam u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 1422b5d600b0SVasundhara Volam int i; 1423b5d600b0SVasundhara Volam 1424b5d600b0SVasundhara Volam for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 1425b5d600b0SVasundhara Volam dst[i] = le64_to_cpu(src[i]); 1426b5d600b0SVasundhara Volam } 1427bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1428b5d600b0SVasundhara Volam } 1429b5d600b0SVasundhara Volam 14308e202366SMichael Chan static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14318e202366SMichael Chan { 14328e202366SMichael Chan struct bnxt *bp = netdev_priv(dev); 14338e202366SMichael Chan 14348e202366SMichael Chan wol->supported = 0; 14358e202366SMichael Chan wol->wolopts = 0; 14368e202366SMichael Chan memset(&wol->sopass, 0, sizeof(wol->sopass)); 14378e202366SMichael Chan if (bp->flags & BNXT_FLAG_WOL_CAP) { 14388e202366SMichael Chan wol->supported = WAKE_MAGIC; 14398e202366SMichael Chan if (bp->wol) 14408e202366SMichael Chan wol->wolopts = WAKE_MAGIC; 14418e202366SMichael Chan } 14428e202366SMichael Chan } 14438e202366SMichael Chan 14445282db6cSMichael Chan static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14455282db6cSMichael Chan { 14465282db6cSMichael Chan struct bnxt *bp = netdev_priv(dev); 14475282db6cSMichael Chan 14485282db6cSMichael Chan if (wol->wolopts & ~WAKE_MAGIC) 14495282db6cSMichael Chan return -EINVAL; 14505282db6cSMichael Chan 14515282db6cSMichael Chan if (wol->wolopts & WAKE_MAGIC) { 14525282db6cSMichael Chan if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 14535282db6cSMichael Chan return -EINVAL; 14545282db6cSMichael Chan if (!bp->wol) { 14555282db6cSMichael Chan if (bnxt_hwrm_alloc_wol_fltr(bp)) 14565282db6cSMichael Chan return -EBUSY; 14575282db6cSMichael Chan bp->wol = 1; 14585282db6cSMichael Chan } 14595282db6cSMichael Chan } else { 14605282db6cSMichael Chan if (bp->wol) { 14615282db6cSMichael Chan if (bnxt_hwrm_free_wol_fltr(bp)) 14625282db6cSMichael Chan return -EBUSY; 14635282db6cSMichael Chan bp->wol = 0; 14645282db6cSMichael Chan } 14655282db6cSMichael Chan } 14665282db6cSMichael Chan return 0; 14675282db6cSMichael Chan } 14685282db6cSMichael Chan 1469170ce013SMichael Chan u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 1470c0c050c5SMichael Chan { 1471c0c050c5SMichael Chan u32 speed_mask = 0; 1472c0c050c5SMichael Chan 1473c0c050c5SMichael Chan /* TODO: support 25GB, 40GB, 50GB with different cable type */ 1474c0c050c5SMichael Chan /* set the advertised speeds */ 1475c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 1476c0c050c5SMichael Chan speed_mask |= ADVERTISED_100baseT_Full; 1477c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 1478c0c050c5SMichael Chan speed_mask |= ADVERTISED_1000baseT_Full; 1479c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 1480c0c050c5SMichael Chan speed_mask |= ADVERTISED_2500baseX_Full; 1481c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 1482c0c050c5SMichael Chan speed_mask |= ADVERTISED_10000baseT_Full; 1483c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 14841c49c421SMichael Chan speed_mask |= ADVERTISED_40000baseCR4_Full; 148527c4d578SMichael Chan 148627c4d578SMichael Chan if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 148727c4d578SMichael Chan speed_mask |= ADVERTISED_Pause; 148827c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_TX) 148927c4d578SMichael Chan speed_mask |= ADVERTISED_Asym_Pause; 149027c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_RX) 149127c4d578SMichael Chan speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 149227c4d578SMichael Chan 1493c0c050c5SMichael Chan return speed_mask; 1494c0c050c5SMichael Chan } 1495c0c050c5SMichael Chan 149600c04a92SMichael Chan #define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 149700c04a92SMichael Chan { \ 149800c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 149900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150000c04a92SMichael Chan 100baseT_Full); \ 150100c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 150200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150300c04a92SMichael Chan 1000baseT_Full); \ 150400c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 150500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150600c04a92SMichael Chan 10000baseT_Full); \ 150700c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 150800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 150900c04a92SMichael Chan 25000baseCR_Full); \ 151000c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 151100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151200c04a92SMichael Chan 40000baseCR4_Full);\ 151300c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 151400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151500c04a92SMichael Chan 50000baseCR2_Full);\ 151638a21b34SDeepak Khungar if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 151738a21b34SDeepak Khungar ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151838a21b34SDeepak Khungar 100000baseCR4_Full);\ 151900c04a92SMichael Chan if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 152000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152100c04a92SMichael Chan Pause); \ 152200c04a92SMichael Chan if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 152300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode( \ 152400c04a92SMichael Chan lk_ksettings, name, Asym_Pause);\ 152500c04a92SMichael Chan } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 152600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152700c04a92SMichael Chan Asym_Pause); \ 152800c04a92SMichael Chan } \ 152900c04a92SMichael Chan } 153000c04a92SMichael Chan 153100c04a92SMichael Chan #define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 153200c04a92SMichael Chan { \ 153300c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 153400c04a92SMichael Chan 100baseT_Full) || \ 153500c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 153600c04a92SMichael Chan 100baseT_Half)) \ 153700c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 153800c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 153900c04a92SMichael Chan 1000baseT_Full) || \ 154000c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154100c04a92SMichael Chan 1000baseT_Half)) \ 154200c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 154300c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154400c04a92SMichael Chan 10000baseT_Full)) \ 154500c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 154600c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154700c04a92SMichael Chan 25000baseCR_Full)) \ 154800c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 154900c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155000c04a92SMichael Chan 40000baseCR4_Full)) \ 155100c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 155200c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155300c04a92SMichael Chan 50000baseCR2_Full)) \ 155400c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 155538a21b34SDeepak Khungar if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155638a21b34SDeepak Khungar 100000baseCR4_Full)) \ 155738a21b34SDeepak Khungar (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 155800c04a92SMichael Chan } 155900c04a92SMichael Chan 1560532262baSEdwin Peer #define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1561532262baSEdwin Peer { \ 1562532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 1563532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1564532262baSEdwin Peer 50000baseCR_Full); \ 1565532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 1566532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1567532262baSEdwin Peer 100000baseCR2_Full);\ 1568532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 1569532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1570532262baSEdwin Peer 200000baseCR4_Full);\ 1571532262baSEdwin Peer } 1572532262baSEdwin Peer 1573532262baSEdwin Peer #define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1574532262baSEdwin Peer { \ 1575532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1576532262baSEdwin Peer 50000baseCR_Full)) \ 1577532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 1578532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1579532262baSEdwin Peer 100000baseCR2_Full)) \ 1580532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 1581532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1582532262baSEdwin Peer 200000baseCR4_Full)) \ 1583532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 1584532262baSEdwin Peer } 1585532262baSEdwin Peer 15868b277589SMichael Chan static void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 15878b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 15888b277589SMichael Chan { 15898b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 15908b277589SMichael Chan 15918b277589SMichael Chan if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 15928b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 15938b277589SMichael Chan lk_ksettings->link_modes.advertising); 15948b277589SMichael Chan return; 15958b277589SMichael Chan } 15968b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 15978b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 15988b277589SMichael Chan lk_ksettings->link_modes.advertising); 15998b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 16008b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16018b277589SMichael Chan lk_ksettings->link_modes.advertising); 16028b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 16038b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16048b277589SMichael Chan lk_ksettings->link_modes.advertising); 16058b277589SMichael Chan } 16068b277589SMichael Chan 160700c04a92SMichael Chan static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 160800c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 160927c4d578SMichael Chan { 161068515a18SMichael Chan u16 fw_speeds = link_info->advertising; 161127c4d578SMichael Chan u8 fw_pause = 0; 161227c4d578SMichael Chan 161327c4d578SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 161427c4d578SMichael Chan fw_pause = link_info->auto_pause_setting; 161527c4d578SMichael Chan 161600c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 1617532262baSEdwin Peer fw_speeds = link_info->advertising_pam4; 1618532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 16198b277589SMichael Chan bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 162027c4d578SMichael Chan } 162127c4d578SMichael Chan 162200c04a92SMichael Chan static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 162300c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16243277360eSMichael Chan { 16253277360eSMichael Chan u16 fw_speeds = link_info->lp_auto_link_speeds; 16263277360eSMichael Chan u8 fw_pause = 0; 16273277360eSMichael Chan 16283277360eSMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 16293277360eSMichael Chan fw_pause = link_info->lp_pause; 16303277360eSMichael Chan 163100c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 163200c04a92SMichael Chan lp_advertising); 1633532262baSEdwin Peer fw_speeds = link_info->lp_auto_pam4_link_speeds; 1634532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 16353277360eSMichael Chan } 16363277360eSMichael Chan 16378b277589SMichael Chan static void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 16388b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16398b277589SMichael Chan { 16408b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16418b277589SMichael Chan 16428b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 16438b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16448b277589SMichael Chan lk_ksettings->link_modes.supported); 16458b277589SMichael Chan return; 16468b277589SMichael Chan } 16478b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 16488b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16498b277589SMichael Chan lk_ksettings->link_modes.supported); 16508b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 16518b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16528b277589SMichael Chan lk_ksettings->link_modes.supported); 16538b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 16548b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16558b277589SMichael Chan lk_ksettings->link_modes.supported); 16568b277589SMichael Chan } 16578b277589SMichael Chan 165800c04a92SMichael Chan static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 165900c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16604b32caccSMichael Chan { 16614b32caccSMichael Chan u16 fw_speeds = link_info->support_speeds; 16624b32caccSMichael Chan 166300c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 1664532262baSEdwin Peer fw_speeds = link_info->support_pam4_speeds; 1665532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16664b32caccSMichael Chan 166700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause); 166800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 166900c04a92SMichael Chan Asym_Pause); 167093ed8117SMichael Chan 1671532262baSEdwin Peer if (link_info->support_auto_speeds || 1672532262baSEdwin Peer link_info->support_pam4_auto_speeds) 167300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 167400c04a92SMichael Chan Autoneg); 16758b277589SMichael Chan bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 167693ed8117SMichael Chan } 167793ed8117SMichael Chan 1678c0c050c5SMichael Chan u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 1679c0c050c5SMichael Chan { 1680c0c050c5SMichael Chan switch (fw_link_speed) { 1681c0c050c5SMichael Chan case BNXT_LINK_SPEED_100MB: 1682c0c050c5SMichael Chan return SPEED_100; 1683c0c050c5SMichael Chan case BNXT_LINK_SPEED_1GB: 1684c0c050c5SMichael Chan return SPEED_1000; 1685c0c050c5SMichael Chan case BNXT_LINK_SPEED_2_5GB: 1686c0c050c5SMichael Chan return SPEED_2500; 1687c0c050c5SMichael Chan case BNXT_LINK_SPEED_10GB: 1688c0c050c5SMichael Chan return SPEED_10000; 1689c0c050c5SMichael Chan case BNXT_LINK_SPEED_20GB: 1690c0c050c5SMichael Chan return SPEED_20000; 1691c0c050c5SMichael Chan case BNXT_LINK_SPEED_25GB: 1692c0c050c5SMichael Chan return SPEED_25000; 1693c0c050c5SMichael Chan case BNXT_LINK_SPEED_40GB: 1694c0c050c5SMichael Chan return SPEED_40000; 1695c0c050c5SMichael Chan case BNXT_LINK_SPEED_50GB: 1696c0c050c5SMichael Chan return SPEED_50000; 169738a21b34SDeepak Khungar case BNXT_LINK_SPEED_100GB: 169838a21b34SDeepak Khungar return SPEED_100000; 1699c0c050c5SMichael Chan default: 1700c0c050c5SMichael Chan return SPEED_UNKNOWN; 1701c0c050c5SMichael Chan } 1702c0c050c5SMichael Chan } 1703c0c050c5SMichael Chan 170400c04a92SMichael Chan static int bnxt_get_link_ksettings(struct net_device *dev, 170500c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 1706c0c050c5SMichael Chan { 1707c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1708c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 170900c04a92SMichael Chan struct ethtool_link_settings *base = &lk_ksettings->base; 171000c04a92SMichael Chan u32 ethtool_speed; 1711c0c050c5SMichael Chan 171200c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 1713e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 171400c04a92SMichael Chan bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 1715c0c050c5SMichael Chan 171600c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 1717b763499eSMichael Chan if (link_info->autoneg) { 171800c04a92SMichael Chan bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 171900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, 172000c04a92SMichael Chan advertising, Autoneg); 172100c04a92SMichael Chan base->autoneg = AUTONEG_ENABLE; 172200c04a92SMichael Chan base->duplex = DUPLEX_UNKNOWN; 172383d8f5e9SMichael Chan if (link_info->phy_link_status == BNXT_LINK_LINK) { 172483d8f5e9SMichael Chan bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 172583d8f5e9SMichael Chan if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 172600c04a92SMichael Chan base->duplex = DUPLEX_FULL; 172729c262feSMichael Chan else 172800c04a92SMichael Chan base->duplex = DUPLEX_HALF; 172983d8f5e9SMichael Chan } 173083d8f5e9SMichael Chan ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 1731c0c050c5SMichael Chan } else { 173200c04a92SMichael Chan base->autoneg = AUTONEG_DISABLE; 173329c262feSMichael Chan ethtool_speed = 173429c262feSMichael Chan bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 173500c04a92SMichael Chan base->duplex = DUPLEX_HALF; 173629c262feSMichael Chan if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 173700c04a92SMichael Chan base->duplex = DUPLEX_FULL; 1738c0c050c5SMichael Chan } 173900c04a92SMichael Chan base->speed = ethtool_speed; 1740c0c050c5SMichael Chan 174100c04a92SMichael Chan base->port = PORT_NONE; 1742c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 174300c04a92SMichael Chan base->port = PORT_TP; 174400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 174500c04a92SMichael Chan TP); 174600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 174700c04a92SMichael Chan TP); 1748c0c050c5SMichael Chan } else { 174900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 175000c04a92SMichael Chan FIBRE); 175100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 175200c04a92SMichael Chan FIBRE); 1753c0c050c5SMichael Chan 1754c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 175500c04a92SMichael Chan base->port = PORT_DA; 1756c0c050c5SMichael Chan else if (link_info->media_type == 1757c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 175800c04a92SMichael Chan base->port = PORT_FIBRE; 1759c0c050c5SMichael Chan } 176000c04a92SMichael Chan base->phy_address = link_info->phy_addr; 1761e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1762c0c050c5SMichael Chan 1763c0c050c5SMichael Chan return 0; 1764c0c050c5SMichael Chan } 1765c0c050c5SMichael Chan 1766f00530bfSEdwin Peer static int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 1767c0c050c5SMichael Chan { 17689d9cee08SMichael Chan struct bnxt *bp = netdev_priv(dev); 17699d9cee08SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 1770532262baSEdwin Peer u16 support_pam4_spds = link_info->support_pam4_speeds; 17719d9cee08SMichael Chan u16 support_spds = link_info->support_speeds; 1772532262baSEdwin Peer u8 sig_mode = BNXT_SIG_MODE_NRZ; 1773f00530bfSEdwin Peer u16 fw_speed = 0; 17749d9cee08SMichael Chan 1775c0c050c5SMichael Chan switch (ethtool_speed) { 1776c0c050c5SMichael Chan case SPEED_100: 17779d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 1778f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17799d9cee08SMichael Chan break; 1780c0c050c5SMichael Chan case SPEED_1000: 17819d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 1782f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 17839d9cee08SMichael Chan break; 1784c0c050c5SMichael Chan case SPEED_2500: 17859d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 1786f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 17879d9cee08SMichael Chan break; 1788c0c050c5SMichael Chan case SPEED_10000: 17899d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 1790f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 17919d9cee08SMichael Chan break; 1792c0c050c5SMichael Chan case SPEED_20000: 17939d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 1794f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 17959d9cee08SMichael Chan break; 1796c0c050c5SMichael Chan case SPEED_25000: 17979d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 1798f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 17999d9cee08SMichael Chan break; 1800c0c050c5SMichael Chan case SPEED_40000: 18019d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 1802f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 18039d9cee08SMichael Chan break; 1804c0c050c5SMichael Chan case SPEED_50000: 1805532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 1806f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 1807532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 1808532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 1809532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1810532262baSEdwin Peer } 18119d9cee08SMichael Chan break; 181238a21b34SDeepak Khungar case SPEED_100000: 1813532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 1814f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 1815532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 1816532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 1817532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1818532262baSEdwin Peer } 1819532262baSEdwin Peer break; 1820532262baSEdwin Peer case SPEED_200000: 1821532262baSEdwin Peer if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 1822532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 1823532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1824532262baSEdwin Peer } 1825c0c050c5SMichael Chan break; 1826c0c050c5SMichael Chan } 1827f00530bfSEdwin Peer 1828f00530bfSEdwin Peer if (!fw_speed) { 1829f00530bfSEdwin Peer netdev_err(dev, "unsupported speed!\n"); 1830f00530bfSEdwin Peer return -EINVAL; 1831f00530bfSEdwin Peer } 1832f00530bfSEdwin Peer 1833745b5c65SEdwin Peer if (link_info->req_link_speed == fw_speed && 1834745b5c65SEdwin Peer link_info->req_signal_mode == sig_mode && 1835745b5c65SEdwin Peer link_info->autoneg == 0) 1836745b5c65SEdwin Peer return -EALREADY; 1837745b5c65SEdwin Peer 1838f00530bfSEdwin Peer link_info->req_link_speed = fw_speed; 1839532262baSEdwin Peer link_info->req_signal_mode = sig_mode; 1840f00530bfSEdwin Peer link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 1841f00530bfSEdwin Peer link_info->autoneg = 0; 1842f00530bfSEdwin Peer link_info->advertising = 0; 1843532262baSEdwin Peer link_info->advertising_pam4 = 0; 1844f00530bfSEdwin Peer 1845f00530bfSEdwin Peer return 0; 1846c0c050c5SMichael Chan } 1847c0c050c5SMichael Chan 1848939f7f0cSMichael Chan u16 bnxt_get_fw_auto_link_speeds(u32 advertising) 1849c0c050c5SMichael Chan { 1850c0c050c5SMichael Chan u16 fw_speed_mask = 0; 1851c0c050c5SMichael Chan 1852c0c050c5SMichael Chan /* only support autoneg at speed 100, 1000, and 10000 */ 1853c0c050c5SMichael Chan if (advertising & (ADVERTISED_100baseT_Full | 1854c0c050c5SMichael Chan ADVERTISED_100baseT_Half)) { 1855c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 1856c0c050c5SMichael Chan } 1857c0c050c5SMichael Chan if (advertising & (ADVERTISED_1000baseT_Full | 1858c0c050c5SMichael Chan ADVERTISED_1000baseT_Half)) { 1859c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 1860c0c050c5SMichael Chan } 1861c0c050c5SMichael Chan if (advertising & ADVERTISED_10000baseT_Full) 1862c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 1863c0c050c5SMichael Chan 18641c49c421SMichael Chan if (advertising & ADVERTISED_40000baseCR4_Full) 18651c49c421SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18661c49c421SMichael Chan 1867c0c050c5SMichael Chan return fw_speed_mask; 1868c0c050c5SMichael Chan } 1869c0c050c5SMichael Chan 187000c04a92SMichael Chan static int bnxt_set_link_ksettings(struct net_device *dev, 187100c04a92SMichael Chan const struct ethtool_link_ksettings *lk_ksettings) 1872c0c050c5SMichael Chan { 1873c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1874c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 187500c04a92SMichael Chan const struct ethtool_link_settings *base = &lk_ksettings->base; 1876c0c050c5SMichael Chan bool set_pause = false; 187768515a18SMichael Chan u32 speed; 187800c04a92SMichael Chan int rc = 0; 1879c0c050c5SMichael Chan 1880c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 188100c04a92SMichael Chan return -EOPNOTSUPP; 1882c0c050c5SMichael Chan 1883e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 188400c04a92SMichael Chan if (base->autoneg == AUTONEG_ENABLE) { 1885532262baSEdwin Peer link_info->advertising = 0; 1886532262baSEdwin Peer link_info->advertising_pam4 = 0; 1887532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 188800c04a92SMichael Chan advertising); 1889532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 1890532262baSEdwin Peer lk_ksettings, advertising); 1891c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_SPEED; 1892532262baSEdwin Peer if (!link_info->advertising && !link_info->advertising_pam4) { 189393ed8117SMichael Chan link_info->advertising = link_info->support_auto_speeds; 1894532262baSEdwin Peer link_info->advertising_pam4 = 1895532262baSEdwin Peer link_info->support_pam4_auto_speeds; 1896532262baSEdwin Peer } 1897c0c050c5SMichael Chan /* any change to autoneg will cause link change, therefore the 1898c0c050c5SMichael Chan * driver should put back the original pause setting in autoneg 1899c0c050c5SMichael Chan */ 1900c0c050c5SMichael Chan set_pause = true; 1901c0c050c5SMichael Chan } else { 190203efbec0SMichael Chan u8 phy_type = link_info->phy_type; 19039d9cee08SMichael Chan 190403efbec0SMichael Chan if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 190503efbec0SMichael Chan phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 190603efbec0SMichael Chan link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 190703efbec0SMichael Chan netdev_err(dev, "10GBase-T devices must autoneg\n"); 190803efbec0SMichael Chan rc = -EINVAL; 190903efbec0SMichael Chan goto set_setting_exit; 191003efbec0SMichael Chan } 191100c04a92SMichael Chan if (base->duplex == DUPLEX_HALF) { 1912c0c050c5SMichael Chan netdev_err(dev, "HALF DUPLEX is not supported!\n"); 1913c0c050c5SMichael Chan rc = -EINVAL; 1914c0c050c5SMichael Chan goto set_setting_exit; 1915c0c050c5SMichael Chan } 191600c04a92SMichael Chan speed = base->speed; 1917f00530bfSEdwin Peer rc = bnxt_force_link_speed(dev, speed); 1918745b5c65SEdwin Peer if (rc) { 1919745b5c65SEdwin Peer if (rc == -EALREADY) 1920745b5c65SEdwin Peer rc = 0; 19219d9cee08SMichael Chan goto set_setting_exit; 19229d9cee08SMichael Chan } 1923745b5c65SEdwin Peer } 1924c0c050c5SMichael Chan 1925c0c050c5SMichael Chan if (netif_running(dev)) 1926939f7f0cSMichael Chan rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 1927c0c050c5SMichael Chan 1928c0c050c5SMichael Chan set_setting_exit: 1929e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1930c0c050c5SMichael Chan return rc; 1931c0c050c5SMichael Chan } 1932c0c050c5SMichael Chan 19338b277589SMichael Chan static int bnxt_get_fecparam(struct net_device *dev, 19348b277589SMichael Chan struct ethtool_fecparam *fec) 19358b277589SMichael Chan { 19368b277589SMichael Chan struct bnxt *bp = netdev_priv(dev); 19378b277589SMichael Chan struct bnxt_link_info *link_info; 19388b277589SMichael Chan u8 active_fec; 19398b277589SMichael Chan u16 fec_cfg; 19408b277589SMichael Chan 19418b277589SMichael Chan link_info = &bp->link_info; 19428b277589SMichael Chan fec_cfg = link_info->fec_cfg; 19438b277589SMichael Chan active_fec = link_info->active_fec_sig_mode & 19448b277589SMichael Chan PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19458b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 19468b277589SMichael Chan fec->fec = ETHTOOL_FEC_NONE; 19478b277589SMichael Chan fec->active_fec = ETHTOOL_FEC_NONE; 19488b277589SMichael Chan return 0; 19498b277589SMichael Chan } 19508b277589SMichael Chan if (fec_cfg & BNXT_FEC_AUTONEG) 19518b277589SMichael Chan fec->fec |= ETHTOOL_FEC_AUTO; 19528b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19538b277589SMichael Chan fec->fec |= ETHTOOL_FEC_BASER; 19548b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 19558b277589SMichael Chan fec->fec |= ETHTOOL_FEC_RS; 19568b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 19578b277589SMichael Chan fec->fec |= ETHTOOL_FEC_LLRS; 19588b277589SMichael Chan 19598b277589SMichael Chan switch (active_fec) { 19608b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19618b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_BASER; 19628b277589SMichael Chan break; 19638b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19648b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19658b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19668b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_RS; 19678b277589SMichael Chan break; 19688b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19698b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19708b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_LLRS; 19718b277589SMichael Chan break; 1972*84d3c83eSSomnath Kotur case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 1973*84d3c83eSSomnath Kotur fec->active_fec |= ETHTOOL_FEC_OFF; 1974*84d3c83eSSomnath Kotur break; 19758b277589SMichael Chan } 19768b277589SMichael Chan return 0; 19778b277589SMichael Chan } 19788b277589SMichael Chan 1979c9ca5c3aSJakub Kicinski static void bnxt_get_fec_stats(struct net_device *dev, 1980c9ca5c3aSJakub Kicinski struct ethtool_fec_stats *fec_stats) 1981c9ca5c3aSJakub Kicinski { 1982c9ca5c3aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 1983c9ca5c3aSJakub Kicinski u64 *rx; 1984c9ca5c3aSJakub Kicinski 1985c9ca5c3aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 1986c9ca5c3aSJakub Kicinski return; 1987c9ca5c3aSJakub Kicinski 1988c9ca5c3aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 1989c9ca5c3aSJakub Kicinski fec_stats->corrected_bits.total = 1990c9ca5c3aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 1991c9ca5c3aSJakub Kicinski } 1992c9ca5c3aSJakub Kicinski 1993ccd6a9dcSMichael Chan static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 1994ccd6a9dcSMichael Chan u32 fec) 1995ccd6a9dcSMichael Chan { 1996ccd6a9dcSMichael Chan u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 1997ccd6a9dcSMichael Chan 1998ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_BASER) 1999ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 2000ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_RS) 2001ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_RS_ON(link_info); 2002ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_LLRS) 2003ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_LLRS_ON; 2004ccd6a9dcSMichael Chan return fw_fec; 2005ccd6a9dcSMichael Chan } 2006ccd6a9dcSMichael Chan 2007ccd6a9dcSMichael Chan static int bnxt_set_fecparam(struct net_device *dev, 2008ccd6a9dcSMichael Chan struct ethtool_fecparam *fecparam) 2009ccd6a9dcSMichael Chan { 2010bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 2011ccd6a9dcSMichael Chan struct bnxt *bp = netdev_priv(dev); 2012ccd6a9dcSMichael Chan struct bnxt_link_info *link_info; 2013ccd6a9dcSMichael Chan u32 new_cfg, fec = fecparam->fec; 2014ccd6a9dcSMichael Chan u16 fec_cfg; 2015ccd6a9dcSMichael Chan int rc; 2016ccd6a9dcSMichael Chan 2017ccd6a9dcSMichael Chan link_info = &bp->link_info; 2018ccd6a9dcSMichael Chan fec_cfg = link_info->fec_cfg; 2019ccd6a9dcSMichael Chan if (fec_cfg & BNXT_FEC_NONE) 2020ccd6a9dcSMichael Chan return -EOPNOTSUPP; 2021ccd6a9dcSMichael Chan 2022ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_OFF) { 2023ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 2024ccd6a9dcSMichael Chan BNXT_FEC_ALL_OFF(link_info); 2025ccd6a9dcSMichael Chan goto apply_fec; 2026ccd6a9dcSMichael Chan } 2027ccd6a9dcSMichael Chan if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 2028ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 2029ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 2030ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 2031ccd6a9dcSMichael Chan return -EINVAL; 2032ccd6a9dcSMichael Chan 2033ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_AUTO) { 2034ccd6a9dcSMichael Chan if (!link_info->autoneg) 2035ccd6a9dcSMichael Chan return -EINVAL; 2036ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 2037ccd6a9dcSMichael Chan } else { 2038ccd6a9dcSMichael Chan new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 2039ccd6a9dcSMichael Chan } 2040ccd6a9dcSMichael Chan 2041ccd6a9dcSMichael Chan apply_fec: 2042bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 2043bbf33d1dSEdwin Peer if (rc) 2044bbf33d1dSEdwin Peer return rc; 2045bbf33d1dSEdwin Peer req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 2046bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2047ccd6a9dcSMichael Chan /* update current settings */ 2048ccd6a9dcSMichael Chan if (!rc) { 2049ccd6a9dcSMichael Chan mutex_lock(&bp->link_lock); 2050ccd6a9dcSMichael Chan bnxt_update_link(bp, false); 2051ccd6a9dcSMichael Chan mutex_unlock(&bp->link_lock); 2052ccd6a9dcSMichael Chan } 2053ccd6a9dcSMichael Chan return rc; 2054ccd6a9dcSMichael Chan } 2055ccd6a9dcSMichael Chan 2056c0c050c5SMichael Chan static void bnxt_get_pauseparam(struct net_device *dev, 2057c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2058c0c050c5SMichael Chan { 2059c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2060c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2061c0c050c5SMichael Chan 2062c0c050c5SMichael Chan if (BNXT_VF(bp)) 2063c0c050c5SMichael Chan return; 2064b763499eSMichael Chan epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20653c02d1bbSMichael Chan epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20663c02d1bbSMichael Chan epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 2067c0c050c5SMichael Chan } 2068c0c050c5SMichael Chan 2069423cffcfSJakub Kicinski static void bnxt_get_pause_stats(struct net_device *dev, 2070423cffcfSJakub Kicinski struct ethtool_pause_stats *epstat) 2071423cffcfSJakub Kicinski { 2072423cffcfSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2073423cffcfSJakub Kicinski u64 *rx, *tx; 2074423cffcfSJakub Kicinski 2075423cffcfSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 2076423cffcfSJakub Kicinski return; 2077423cffcfSJakub Kicinski 2078423cffcfSJakub Kicinski rx = bp->port_stats.sw_stats; 2079423cffcfSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 2080423cffcfSJakub Kicinski 2081423cffcfSJakub Kicinski epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 2082423cffcfSJakub Kicinski epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 2083423cffcfSJakub Kicinski } 2084423cffcfSJakub Kicinski 2085c0c050c5SMichael Chan static int bnxt_set_pauseparam(struct net_device *dev, 2086c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2087c0c050c5SMichael Chan { 2088c0c050c5SMichael Chan int rc = 0; 2089c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2090c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2091c0c050c5SMichael Chan 2092c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 209375362a3fSMichael Chan return -EOPNOTSUPP; 2094c0c050c5SMichael Chan 2095a5390690SMichael Chan mutex_lock(&bp->link_lock); 2096c0c050c5SMichael Chan if (epause->autoneg) { 2097a5390690SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 2098a5390690SMichael Chan rc = -EINVAL; 2099a5390690SMichael Chan goto pause_exit; 2100a5390690SMichael Chan } 2101b763499eSMichael Chan 2102c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 2103c9ee9516SMichael Chan if (bp->hwrm_spec_code >= 0x10201) 2104c9ee9516SMichael Chan link_info->req_flow_ctrl = 2105c9ee9516SMichael Chan PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE; 2106c0c050c5SMichael Chan } else { 2107c0c050c5SMichael Chan /* when transition from auto pause to force pause, 2108c0c050c5SMichael Chan * force a link change 2109c0c050c5SMichael Chan */ 2110c0c050c5SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 2111c0c050c5SMichael Chan link_info->force_link_chng = true; 2112c0c050c5SMichael Chan link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 2113c9ee9516SMichael Chan link_info->req_flow_ctrl = 0; 2114c0c050c5SMichael Chan } 2115c0c050c5SMichael Chan if (epause->rx_pause) 2116c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 2117c0c050c5SMichael Chan 2118c0c050c5SMichael Chan if (epause->tx_pause) 2119c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 2120c0c050c5SMichael Chan 2121a5390690SMichael Chan if (netif_running(dev)) 2122c0c050c5SMichael Chan rc = bnxt_hwrm_set_pause(bp); 2123a5390690SMichael Chan 2124a5390690SMichael Chan pause_exit: 2125163e9ef6SVasundhara Volam mutex_unlock(&bp->link_lock); 2126c0c050c5SMichael Chan return rc; 2127c0c050c5SMichael Chan } 2128c0c050c5SMichael Chan 2129c0c050c5SMichael Chan static u32 bnxt_get_link(struct net_device *dev) 2130c0c050c5SMichael Chan { 2131c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2132c0c050c5SMichael Chan 2133c0c050c5SMichael Chan /* TODO: handle MF, VF, driver close case */ 2134c0c050c5SMichael Chan return bp->link_info.link_up; 2135c0c050c5SMichael Chan } 2136c0c050c5SMichael Chan 21374933f675SVasundhara Volam int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 21384933f675SVasundhara Volam struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 21394933f675SVasundhara Volam { 2140bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_output *resp; 2141bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_input *req; 21424933f675SVasundhara Volam int rc; 21434933f675SVasundhara Volam 21440ae0a779SVasundhara Volam if (BNXT_VF(bp)) 21450ae0a779SVasundhara Volam return -EOPNOTSUPP; 21460ae0a779SVasundhara Volam 2147bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 2148bbf33d1dSEdwin Peer if (rc) 2149bbf33d1dSEdwin Peer return rc; 2150bbf33d1dSEdwin Peer 2151bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 2152bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 21534933f675SVasundhara Volam if (!rc) 21544933f675SVasundhara Volam memcpy(nvm_dev_info, resp, sizeof(*resp)); 2155bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 21564933f675SVasundhara Volam return rc; 21574933f675SVasundhara Volam } 21584933f675SVasundhara Volam 2159b3b0ddd0SMichael Chan static void bnxt_print_admin_err(struct bnxt *bp) 2160b3b0ddd0SMichael Chan { 2161b3b0ddd0SMichael Chan netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 2162b3b0ddd0SMichael Chan } 2163b3b0ddd0SMichael Chan 21645ac67d8bSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21655ac67d8bSRob Swindell u16 ext, u16 *index, u32 *item_length, 21665ac67d8bSRob Swindell u32 *data_length); 21675ac67d8bSRob Swindell 2168bbf33d1dSEdwin Peer static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 216993ff3435SPavan Chebbi u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 217093ff3435SPavan Chebbi u32 dir_item_len, const u8 *data, 2171c0c050c5SMichael Chan size_t data_len) 2172c0c050c5SMichael Chan { 2173c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2174bbf33d1dSEdwin Peer struct hwrm_nvm_write_input *req; 2175c0c050c5SMichael Chan int rc; 2176c0c050c5SMichael Chan 2177bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 2178bbf33d1dSEdwin Peer if (rc) 2179bbf33d1dSEdwin Peer return rc; 2180c0c050c5SMichael Chan 218193ff3435SPavan Chebbi if (data_len && data) { 2182bbf33d1dSEdwin Peer dma_addr_t dma_handle; 2183bbf33d1dSEdwin Peer u8 *kmem; 2184c0c050c5SMichael Chan 2185bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 2186bbf33d1dSEdwin Peer if (!kmem) { 2187bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2188c0c050c5SMichael Chan return -ENOMEM; 218993ff3435SPavan Chebbi } 2190c0c050c5SMichael Chan 2191bbf33d1dSEdwin Peer req->dir_data_length = cpu_to_le32(data_len); 2192bbf33d1dSEdwin Peer 2193bbf33d1dSEdwin Peer memcpy(kmem, data, data_len); 2194bbf33d1dSEdwin Peer req->host_src_addr = cpu_to_le64(dma_handle); 2195bbf33d1dSEdwin Peer } 2196bbf33d1dSEdwin Peer 2197bce9a0b7SEdwin Peer hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 2198bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(dir_type); 2199bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(dir_ordinal); 2200bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(dir_ext); 2201bbf33d1dSEdwin Peer req->dir_attr = cpu_to_le16(dir_attr); 2202bbf33d1dSEdwin Peer req->dir_item_length = cpu_to_le32(dir_item_len); 2203bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2204c0c050c5SMichael Chan 2205d4f1420dSMichael Chan if (rc == -EACCES) 2206b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2207c0c050c5SMichael Chan return rc; 2208c0c050c5SMichael Chan } 2209c0c050c5SMichael Chan 22108f6c5e4dSEdwin Peer int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 221195fec034SEdwin Peer u8 self_reset, u8 flags) 2212d2d6318cSRob Swindell { 22137c675421SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 2214bbf33d1dSEdwin Peer struct hwrm_fw_reset_input *req; 22157c675421SVasundhara Volam int rc; 2216d2d6318cSRob Swindell 2217892a662fSEdwin Peer if (!bnxt_hwrm_reset_permitted(bp)) { 2218892a662fSEdwin Peer netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 2219892a662fSEdwin Peer return -EPERM; 2220892a662fSEdwin Peer } 2221892a662fSEdwin Peer 2222bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 2223bbf33d1dSEdwin Peer if (rc) 2224bbf33d1dSEdwin Peer return rc; 2225d2d6318cSRob Swindell 2226bbf33d1dSEdwin Peer req->embedded_proc_type = proc_type; 2227bbf33d1dSEdwin Peer req->selfrst_status = self_reset; 2228bbf33d1dSEdwin Peer req->flags = flags; 222995fec034SEdwin Peer 22308cec0940SEdwin Peer if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 2231bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 22328cec0940SEdwin Peer } else { 2233bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 223495fec034SEdwin Peer if (rc == -EACCES) 223595fec034SEdwin Peer bnxt_print_admin_err(bp); 22368cec0940SEdwin Peer } 223795fec034SEdwin Peer return rc; 223895fec034SEdwin Peer } 223995fec034SEdwin Peer 224094f17e89SEdwin Peer static int bnxt_firmware_reset(struct net_device *dev, 224194f17e89SEdwin Peer enum bnxt_nvm_directory_type dir_type) 224295fec034SEdwin Peer { 224395fec034SEdwin Peer u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 224495fec034SEdwin Peer u8 proc_type, flags = 0; 224595fec034SEdwin Peer 2246d2d6318cSRob Swindell /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 2247d2d6318cSRob Swindell /* (e.g. when firmware isn't already running) */ 2248d2d6318cSRob Swindell switch (dir_type) { 2249d2d6318cSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 2250d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE: 2251d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE_2: 225295fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 2253d2d6318cSRob Swindell /* Self-reset ChiMP upon next PCIe reset: */ 225495fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2255d2d6318cSRob Swindell break; 2256d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_FW: 2257d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 225895fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 225908141e0bSRob Swindell /* Self-reset APE upon next PCIe reset: */ 226095fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2261d2d6318cSRob Swindell break; 2262d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_FW: 2263d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 226495fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 2265d2d6318cSRob Swindell break; 2266d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_FW: 2267d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 226895fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 2269d2d6318cSRob Swindell break; 2270d2d6318cSRob Swindell default: 2271d2d6318cSRob Swindell return -EINVAL; 2272d2d6318cSRob Swindell } 2273d2d6318cSRob Swindell 227495fec034SEdwin Peer return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 2275d2d6318cSRob Swindell } 2276d2d6318cSRob Swindell 227794f17e89SEdwin Peer static int bnxt_firmware_reset_chip(struct net_device *dev) 227894f17e89SEdwin Peer { 227994f17e89SEdwin Peer struct bnxt *bp = netdev_priv(dev); 228094f17e89SEdwin Peer u8 flags = 0; 228194f17e89SEdwin Peer 228294f17e89SEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 228394f17e89SEdwin Peer flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 228494f17e89SEdwin Peer 228594f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, 228694f17e89SEdwin Peer FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 228794f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 228894f17e89SEdwin Peer flags); 228994f17e89SEdwin Peer } 229094f17e89SEdwin Peer 229194f17e89SEdwin Peer static int bnxt_firmware_reset_ap(struct net_device *dev) 229294f17e89SEdwin Peer { 229394f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 229494f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 229594f17e89SEdwin Peer 0); 229694f17e89SEdwin Peer } 229794f17e89SEdwin Peer 2298c0c050c5SMichael Chan static int bnxt_flash_firmware(struct net_device *dev, 2299c0c050c5SMichael Chan u16 dir_type, 2300c0c050c5SMichael Chan const u8 *fw_data, 2301c0c050c5SMichael Chan size_t fw_size) 2302c0c050c5SMichael Chan { 2303c0c050c5SMichael Chan int rc = 0; 2304c0c050c5SMichael Chan u16 code_type; 2305c0c050c5SMichael Chan u32 stored_crc; 2306c0c050c5SMichael Chan u32 calculated_crc; 2307c0c050c5SMichael Chan struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 2308c0c050c5SMichael Chan 2309c0c050c5SMichael Chan switch (dir_type) { 2310c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2311c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2312c0c050c5SMichael Chan code_type = CODE_BOOT; 2313c0c050c5SMichael Chan break; 231493e0b4feSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 231593e0b4feSRob Swindell code_type = CODE_CHIMP_PATCH; 231693e0b4feSRob Swindell break; 23172731d70fSRob Swindell case BNX_DIR_TYPE_APE_FW: 23182731d70fSRob Swindell code_type = CODE_MCTP_PASSTHRU; 23192731d70fSRob Swindell break; 232093e0b4feSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 232193e0b4feSRob Swindell code_type = CODE_APE_PATCH; 232293e0b4feSRob Swindell break; 232393e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_FW: 232493e0b4feSRob Swindell code_type = CODE_KONG_FW; 232593e0b4feSRob Swindell break; 232693e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 232793e0b4feSRob Swindell code_type = CODE_KONG_PATCH; 232893e0b4feSRob Swindell break; 232993e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 233093e0b4feSRob Swindell code_type = CODE_BONO_FW; 233193e0b4feSRob Swindell break; 233293e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 233393e0b4feSRob Swindell code_type = CODE_BONO_PATCH; 233493e0b4feSRob Swindell break; 2335c0c050c5SMichael Chan default: 2336c0c050c5SMichael Chan netdev_err(dev, "Unsupported directory entry type: %u\n", 2337c0c050c5SMichael Chan dir_type); 2338c0c050c5SMichael Chan return -EINVAL; 2339c0c050c5SMichael Chan } 2340c0c050c5SMichael Chan if (fw_size < sizeof(struct bnxt_fw_header)) { 2341c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware file size: %u\n", 2342c0c050c5SMichael Chan (unsigned int)fw_size); 2343c0c050c5SMichael Chan return -EINVAL; 2344c0c050c5SMichael Chan } 2345c0c050c5SMichael Chan if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 2346c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware signature: %08X\n", 2347c0c050c5SMichael Chan le32_to_cpu(header->signature)); 2348c0c050c5SMichael Chan return -EINVAL; 2349c0c050c5SMichael Chan } 2350c0c050c5SMichael Chan if (header->code_type != code_type) { 2351c0c050c5SMichael Chan netdev_err(dev, "Expected firmware type: %d, read: %d\n", 2352c0c050c5SMichael Chan code_type, header->code_type); 2353c0c050c5SMichael Chan return -EINVAL; 2354c0c050c5SMichael Chan } 2355c0c050c5SMichael Chan if (header->device != DEVICE_CUMULUS_FAMILY) { 2356c0c050c5SMichael Chan netdev_err(dev, "Expected firmware device family %d, read: %d\n", 2357c0c050c5SMichael Chan DEVICE_CUMULUS_FAMILY, header->device); 2358c0c050c5SMichael Chan return -EINVAL; 2359c0c050c5SMichael Chan } 2360c0c050c5SMichael Chan /* Confirm the CRC32 checksum of the file: */ 2361c0c050c5SMichael Chan stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 2362c0c050c5SMichael Chan sizeof(stored_crc))); 2363c0c050c5SMichael Chan calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 2364c0c050c5SMichael Chan if (calculated_crc != stored_crc) { 2365c0c050c5SMichael Chan netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 2366c0c050c5SMichael Chan (unsigned long)stored_crc, 2367c0c050c5SMichael Chan (unsigned long)calculated_crc); 2368c0c050c5SMichael Chan return -EINVAL; 2369c0c050c5SMichael Chan } 2370c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2371bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 2372d2d6318cSRob Swindell if (rc == 0) /* Firmware update successful */ 2373d2d6318cSRob Swindell rc = bnxt_firmware_reset(dev, dir_type); 2374d2d6318cSRob Swindell 2375c0c050c5SMichael Chan return rc; 2376c0c050c5SMichael Chan } 2377c0c050c5SMichael Chan 23785ac67d8bSRob Swindell static int bnxt_flash_microcode(struct net_device *dev, 23795ac67d8bSRob Swindell u16 dir_type, 23805ac67d8bSRob Swindell const u8 *fw_data, 23815ac67d8bSRob Swindell size_t fw_size) 23825ac67d8bSRob Swindell { 23835ac67d8bSRob Swindell struct bnxt_ucode_trailer *trailer; 23845ac67d8bSRob Swindell u32 calculated_crc; 23855ac67d8bSRob Swindell u32 stored_crc; 23865ac67d8bSRob Swindell int rc = 0; 23875ac67d8bSRob Swindell 23885ac67d8bSRob Swindell if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 23895ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode file size: %u\n", 23905ac67d8bSRob Swindell (unsigned int)fw_size); 23915ac67d8bSRob Swindell return -EINVAL; 23925ac67d8bSRob Swindell } 23935ac67d8bSRob Swindell trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 23945ac67d8bSRob Swindell sizeof(*trailer))); 23955ac67d8bSRob Swindell if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 23965ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 23975ac67d8bSRob Swindell le32_to_cpu(trailer->sig)); 23985ac67d8bSRob Swindell return -EINVAL; 23995ac67d8bSRob Swindell } 24005ac67d8bSRob Swindell if (le16_to_cpu(trailer->dir_type) != dir_type) { 24015ac67d8bSRob Swindell netdev_err(dev, "Expected microcode type: %d, read: %d\n", 24025ac67d8bSRob Swindell dir_type, le16_to_cpu(trailer->dir_type)); 24035ac67d8bSRob Swindell return -EINVAL; 24045ac67d8bSRob Swindell } 24055ac67d8bSRob Swindell if (le16_to_cpu(trailer->trailer_length) < 24065ac67d8bSRob Swindell sizeof(struct bnxt_ucode_trailer)) { 24075ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer length: %d\n", 24085ac67d8bSRob Swindell le16_to_cpu(trailer->trailer_length)); 24095ac67d8bSRob Swindell return -EINVAL; 24105ac67d8bSRob Swindell } 24115ac67d8bSRob Swindell 24125ac67d8bSRob Swindell /* Confirm the CRC32 checksum of the file: */ 24135ac67d8bSRob Swindell stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 24145ac67d8bSRob Swindell sizeof(stored_crc))); 24155ac67d8bSRob Swindell calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 24165ac67d8bSRob Swindell if (calculated_crc != stored_crc) { 24175ac67d8bSRob Swindell netdev_err(dev, 24185ac67d8bSRob Swindell "CRC32 (%08lX) does not match calculated: %08lX\n", 24195ac67d8bSRob Swindell (unsigned long)stored_crc, 24205ac67d8bSRob Swindell (unsigned long)calculated_crc); 24215ac67d8bSRob Swindell return -EINVAL; 24225ac67d8bSRob Swindell } 24235ac67d8bSRob Swindell rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2424bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 24255ac67d8bSRob Swindell 24265ac67d8bSRob Swindell return rc; 24275ac67d8bSRob Swindell } 24285ac67d8bSRob Swindell 2429c0c050c5SMichael Chan static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 2430c0c050c5SMichael Chan { 2431c0c050c5SMichael Chan switch (dir_type) { 2432c0c050c5SMichael Chan case BNX_DIR_TYPE_CHIMP_PATCH: 2433c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2434c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2435c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_FW: 2436c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_PATCH: 2437c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_FW: 2438c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_PATCH: 243993e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 244093e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 2441c0c050c5SMichael Chan return true; 2442c0c050c5SMichael Chan } 2443c0c050c5SMichael Chan 2444c0c050c5SMichael Chan return false; 2445c0c050c5SMichael Chan } 2446c0c050c5SMichael Chan 24475ac67d8bSRob Swindell static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 2448c0c050c5SMichael Chan { 2449c0c050c5SMichael Chan switch (dir_type) { 2450c0c050c5SMichael Chan case BNX_DIR_TYPE_AVS: 2451c0c050c5SMichael Chan case BNX_DIR_TYPE_EXP_ROM_MBA: 2452c0c050c5SMichael Chan case BNX_DIR_TYPE_PCIE: 2453c0c050c5SMichael Chan case BNX_DIR_TYPE_TSCF_UCODE: 2454c0c050c5SMichael Chan case BNX_DIR_TYPE_EXT_PHY: 2455c0c050c5SMichael Chan case BNX_DIR_TYPE_CCM: 2456c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT: 2457c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 2458c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 2459c0c050c5SMichael Chan return true; 2460c0c050c5SMichael Chan } 2461c0c050c5SMichael Chan 2462c0c050c5SMichael Chan return false; 2463c0c050c5SMichael Chan } 2464c0c050c5SMichael Chan 2465c0c050c5SMichael Chan static bool bnxt_dir_type_is_executable(u16 dir_type) 2466c0c050c5SMichael Chan { 2467c0c050c5SMichael Chan return bnxt_dir_type_is_ape_bin_format(dir_type) || 24685ac67d8bSRob Swindell bnxt_dir_type_is_other_exec_format(dir_type); 2469c0c050c5SMichael Chan } 2470c0c050c5SMichael Chan 2471c0c050c5SMichael Chan static int bnxt_flash_firmware_from_file(struct net_device *dev, 2472c0c050c5SMichael Chan u16 dir_type, 2473c0c050c5SMichael Chan const char *filename) 2474c0c050c5SMichael Chan { 2475c0c050c5SMichael Chan const struct firmware *fw; 2476c0c050c5SMichael Chan int rc; 2477c0c050c5SMichael Chan 2478c0c050c5SMichael Chan rc = request_firmware(&fw, filename, &dev->dev); 2479c0c050c5SMichael Chan if (rc != 0) { 2480c0c050c5SMichael Chan netdev_err(dev, "Error %d requesting firmware file: %s\n", 2481c0c050c5SMichael Chan rc, filename); 2482c0c050c5SMichael Chan return rc; 2483c0c050c5SMichael Chan } 2484ba425800SJason Yan if (bnxt_dir_type_is_ape_bin_format(dir_type)) 2485c0c050c5SMichael Chan rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 2486ba425800SJason Yan else if (bnxt_dir_type_is_other_exec_format(dir_type)) 24875ac67d8bSRob Swindell rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 2488c0c050c5SMichael Chan else 2489c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2490bbf33d1dSEdwin Peer 0, 0, 0, fw->data, fw->size); 2491c0c050c5SMichael Chan release_firmware(fw); 2492c0c050c5SMichael Chan return rc; 2493c0c050c5SMichael Chan } 2494c0c050c5SMichael Chan 2495a86b313eSMichael Chan #define BNXT_PKG_DMA_SIZE 0x40000 2496a86b313eSMichael Chan #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 2497a86b313eSMichael Chan #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 2498a86b313eSMichael Chan 2499b44cfd4fSJacob Keller int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 2500d168f328SVasundhara Volam u32 install_type) 2501c0c050c5SMichael Chan { 2502bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_input *install; 2503bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_output *resp; 2504bbf33d1dSEdwin Peer struct hwrm_nvm_modify_input *modify; 2505a9094ba6SMichael Chan struct bnxt *bp = netdev_priv(dev); 25061432c3f6SPavan Chebbi bool defrag_attempted = false; 2507a9094ba6SMichael Chan dma_addr_t dma_handle; 2508a9094ba6SMichael Chan u8 *kmem = NULL; 2509a86b313eSMichael Chan u32 modify_len; 25105ac67d8bSRob Swindell u32 item_len; 25115ac67d8bSRob Swindell u16 index; 2512bbf33d1dSEdwin Peer int rc; 25135ac67d8bSRob Swindell 25145ac67d8bSRob Swindell bnxt_hwrm_fw_set_time(bp); 25155ac67d8bSRob Swindell 2516bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 2517bbf33d1dSEdwin Peer if (rc) 2518bbf33d1dSEdwin Peer return rc; 2519a9094ba6SMichael Chan 2520a86b313eSMichael Chan /* Try allocating a large DMA buffer first. Older fw will 2521a86b313eSMichael Chan * cause excessive NVRAM erases when using small blocks. 2522a86b313eSMichael Chan */ 2523a86b313eSMichael Chan modify_len = roundup_pow_of_two(fw->size); 2524a86b313eSMichael Chan modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 2525a86b313eSMichael Chan while (1) { 2526bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 2527a86b313eSMichael Chan if (!kmem && modify_len > PAGE_SIZE) 2528a86b313eSMichael Chan modify_len /= 2; 2529a86b313eSMichael Chan else 2530a86b313eSMichael Chan break; 2531a86b313eSMichael Chan } 2532bbf33d1dSEdwin Peer if (!kmem) { 2533bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2534a9094ba6SMichael Chan return -ENOMEM; 2535bbf33d1dSEdwin Peer } 2536a9094ba6SMichael Chan 2537bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 2538bbf33d1dSEdwin Peer if (rc) { 2539bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2540bbf33d1dSEdwin Peer return rc; 2541bbf33d1dSEdwin Peer } 2542a9094ba6SMichael Chan 2543bce9a0b7SEdwin Peer hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 2544bce9a0b7SEdwin Peer hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 2545bbf33d1dSEdwin Peer 2546bbf33d1dSEdwin Peer hwrm_req_hold(bp, modify); 2547bbf33d1dSEdwin Peer modify->host_src_addr = cpu_to_le64(dma_handle); 2548bbf33d1dSEdwin Peer 2549bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, install); 2550a9094ba6SMichael Chan if ((install_type & 0xffff) == 0) 2551a9094ba6SMichael Chan install_type >>= 16; 2552bbf33d1dSEdwin Peer install->install_type = cpu_to_le32(install_type); 2553a9094ba6SMichael Chan 25542e5fb428SPavan Chebbi do { 2555a86b313eSMichael Chan u32 copied = 0, len = modify_len; 2556a86b313eSMichael Chan 255795ec1f47SVasundhara Volam rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 25582e5fb428SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 25592e5fb428SPavan Chebbi BNX_DIR_EXT_NONE, 256095ec1f47SVasundhara Volam &index, &item_len, NULL); 256195ec1f47SVasundhara Volam if (rc) { 25625ac67d8bSRob Swindell netdev_err(dev, "PKG update area not created in nvram\n"); 25632e5fb428SPavan Chebbi break; 25645ac67d8bSRob Swindell } 25655ac67d8bSRob Swindell if (fw->size > item_len) { 25669a005c38SJonathan Lemon netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", 25675ac67d8bSRob Swindell (unsigned long)fw->size); 25685ac67d8bSRob Swindell rc = -EFBIG; 25692e5fb428SPavan Chebbi break; 25702e5fb428SPavan Chebbi } 25712e5fb428SPavan Chebbi 2572bbf33d1dSEdwin Peer modify->dir_idx = cpu_to_le16(index); 25735ac67d8bSRob Swindell 2574a86b313eSMichael Chan if (fw->size > modify_len) 2575bbf33d1dSEdwin Peer modify->flags = BNXT_NVM_MORE_FLAG; 2576a86b313eSMichael Chan while (copied < fw->size) { 2577a86b313eSMichael Chan u32 balance = fw->size - copied; 2578a86b313eSMichael Chan 2579a86b313eSMichael Chan if (balance <= modify_len) { 2580a86b313eSMichael Chan len = balance; 2581a86b313eSMichael Chan if (copied) 2582bbf33d1dSEdwin Peer modify->flags |= BNXT_NVM_LAST_FLAG; 2583a86b313eSMichael Chan } 2584a86b313eSMichael Chan memcpy(kmem, fw->data + copied, len); 2585bbf33d1dSEdwin Peer modify->len = cpu_to_le32(len); 2586bbf33d1dSEdwin Peer modify->offset = cpu_to_le32(copied); 2587bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, modify); 258822630e28SEdwin Peer if (rc) 2589a86b313eSMichael Chan goto pkg_abort; 2590a86b313eSMichael Chan copied += len; 2591a86b313eSMichael Chan } 2592bbf33d1dSEdwin Peer 2593bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 2594cb4d1d62SKshitij Soni 25951432c3f6SPavan Chebbi if (defrag_attempted) { 25961432c3f6SPavan Chebbi /* We have tried to defragment already in the previous 25971432c3f6SPavan Chebbi * iteration. Return with the result for INSTALL_UPDATE 25981432c3f6SPavan Chebbi */ 25991432c3f6SPavan Chebbi break; 26001432c3f6SPavan Chebbi } 26011432c3f6SPavan Chebbi 2602bbf33d1dSEdwin Peer if (rc && ((struct hwrm_err_output *)resp)->cmd_err == 2603dd2ebf34SVasundhara Volam NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { 2604bbf33d1dSEdwin Peer install->flags = 26052e5fb428SPavan Chebbi cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 26062e5fb428SPavan Chebbi 2607bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 26081432c3f6SPavan Chebbi 2609bbf33d1dSEdwin Peer if (rc && ((struct hwrm_err_output *)resp)->cmd_err == 26101432c3f6SPavan Chebbi NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 26111432c3f6SPavan Chebbi /* FW has cleared NVM area, driver will create 26121432c3f6SPavan Chebbi * UPDATE directory and try the flash again 26131432c3f6SPavan Chebbi */ 26141432c3f6SPavan Chebbi defrag_attempted = true; 2615bbf33d1dSEdwin Peer install->flags = 0; 2616bbf33d1dSEdwin Peer rc = bnxt_flash_nvram(bp->dev, 26171432c3f6SPavan Chebbi BNX_DIR_TYPE_UPDATE, 26181432c3f6SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 2619bbf33d1dSEdwin Peer 0, 0, item_len, NULL, 0); 26201432c3f6SPavan Chebbi } else if (rc) { 26211432c3f6SPavan Chebbi netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc); 26221432c3f6SPavan Chebbi } 26231432c3f6SPavan Chebbi } else if (rc) { 26241432c3f6SPavan Chebbi netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc); 2625dd2ebf34SVasundhara Volam } 26261432c3f6SPavan Chebbi } while (defrag_attempted && !rc); 26275ac67d8bSRob Swindell 2628a86b313eSMichael Chan pkg_abort: 2629bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2630bbf33d1dSEdwin Peer hwrm_req_drop(bp, install); 2631bbf33d1dSEdwin Peer 2632bbf33d1dSEdwin Peer if (resp->result) { 26335ac67d8bSRob Swindell netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 2634bbf33d1dSEdwin Peer (s8)resp->result, (int)resp->problem_item); 2635cb4d1d62SKshitij Soni rc = -ENOPKG; 26365ac67d8bSRob Swindell } 263722630e28SEdwin Peer if (rc == -EACCES) 2638b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2639cb4d1d62SKshitij Soni return rc; 2640c0c050c5SMichael Chan } 2641c0c050c5SMichael Chan 2642b44cfd4fSJacob Keller static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 2643b44cfd4fSJacob Keller u32 install_type) 2644b44cfd4fSJacob Keller { 2645b44cfd4fSJacob Keller const struct firmware *fw; 2646b44cfd4fSJacob Keller int rc; 2647b44cfd4fSJacob Keller 2648b44cfd4fSJacob Keller rc = request_firmware(&fw, filename, &dev->dev); 2649b44cfd4fSJacob Keller if (rc != 0) { 2650b44cfd4fSJacob Keller netdev_err(dev, "PKG error %d requesting file: %s\n", 2651b44cfd4fSJacob Keller rc, filename); 2652b44cfd4fSJacob Keller return rc; 2653b44cfd4fSJacob Keller } 2654b44cfd4fSJacob Keller 2655b44cfd4fSJacob Keller rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type); 2656b44cfd4fSJacob Keller 2657b44cfd4fSJacob Keller release_firmware(fw); 2658b44cfd4fSJacob Keller 2659b44cfd4fSJacob Keller return rc; 2660b44cfd4fSJacob Keller } 2661b44cfd4fSJacob Keller 2662c0c050c5SMichael Chan static int bnxt_flash_device(struct net_device *dev, 2663c0c050c5SMichael Chan struct ethtool_flash *flash) 2664c0c050c5SMichael Chan { 2665c0c050c5SMichael Chan if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 2666c0c050c5SMichael Chan netdev_err(dev, "flashdev not supported from a virtual function\n"); 2667c0c050c5SMichael Chan return -EINVAL; 2668c0c050c5SMichael Chan } 2669c0c050c5SMichael Chan 26705ac67d8bSRob Swindell if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 26715ac67d8bSRob Swindell flash->region > 0xffff) 26725ac67d8bSRob Swindell return bnxt_flash_package_from_file(dev, flash->data, 26735ac67d8bSRob Swindell flash->region); 2674c0c050c5SMichael Chan 2675c0c050c5SMichael Chan return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 2676c0c050c5SMichael Chan } 2677c0c050c5SMichael Chan 2678c0c050c5SMichael Chan static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 2679c0c050c5SMichael Chan { 2680bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_output *output; 2681bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_input *req; 2682c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2683c0c050c5SMichael Chan int rc; 2684c0c050c5SMichael Chan 2685bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 2686bbf33d1dSEdwin Peer if (rc) 2687bbf33d1dSEdwin Peer return rc; 2688c0c050c5SMichael Chan 2689bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2690bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2691c0c050c5SMichael Chan if (!rc) { 2692c0c050c5SMichael Chan *entries = le32_to_cpu(output->entries); 2693c0c050c5SMichael Chan *length = le32_to_cpu(output->entry_length); 2694c0c050c5SMichael Chan } 2695bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2696c0c050c5SMichael Chan return rc; 2697c0c050c5SMichael Chan } 2698c0c050c5SMichael Chan 2699c0c050c5SMichael Chan static int bnxt_get_eeprom_len(struct net_device *dev) 2700c0c050c5SMichael Chan { 27014cebbacaSMichael Chan struct bnxt *bp = netdev_priv(dev); 27024cebbacaSMichael Chan 27034cebbacaSMichael Chan if (BNXT_VF(bp)) 27044cebbacaSMichael Chan return 0; 27054cebbacaSMichael Chan 2706c0c050c5SMichael Chan /* The -1 return value allows the entire 32-bit range of offsets to be 2707c0c050c5SMichael Chan * passed via the ethtool command-line utility. 2708c0c050c5SMichael Chan */ 2709c0c050c5SMichael Chan return -1; 2710c0c050c5SMichael Chan } 2711c0c050c5SMichael Chan 2712c0c050c5SMichael Chan static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 2713c0c050c5SMichael Chan { 2714c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2715c0c050c5SMichael Chan int rc; 2716c0c050c5SMichael Chan u32 dir_entries; 2717c0c050c5SMichael Chan u32 entry_length; 2718c0c050c5SMichael Chan u8 *buf; 2719c0c050c5SMichael Chan size_t buflen; 2720c0c050c5SMichael Chan dma_addr_t dma_handle; 2721bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_entries_input *req; 2722c0c050c5SMichael Chan 2723c0c050c5SMichael Chan rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 2724c0c050c5SMichael Chan if (rc != 0) 2725c0c050c5SMichael Chan return rc; 2726c0c050c5SMichael Chan 2727dbbfa96aSVasundhara Volam if (!dir_entries || !entry_length) 2728dbbfa96aSVasundhara Volam return -EIO; 2729dbbfa96aSVasundhara Volam 2730c0c050c5SMichael Chan /* Insert 2 bytes of directory info (count and size of entries) */ 2731c0c050c5SMichael Chan if (len < 2) 2732c0c050c5SMichael Chan return -EINVAL; 2733c0c050c5SMichael Chan 2734c0c050c5SMichael Chan *data++ = dir_entries; 2735c0c050c5SMichael Chan *data++ = entry_length; 2736c0c050c5SMichael Chan len -= 2; 2737c0c050c5SMichael Chan memset(data, 0xff, len); 2738c0c050c5SMichael Chan 2739bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 2740bbf33d1dSEdwin Peer if (rc) 2741bbf33d1dSEdwin Peer return rc; 2742bbf33d1dSEdwin Peer 2743c0c050c5SMichael Chan buflen = dir_entries * entry_length; 2744bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 2745c0c050c5SMichael Chan if (!buf) { 2746bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2747c0c050c5SMichael Chan return -ENOMEM; 2748c0c050c5SMichael Chan } 2749bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2750bbf33d1dSEdwin Peer 2751bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2752bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2753c0c050c5SMichael Chan if (rc == 0) 2754c0c050c5SMichael Chan memcpy(data, buf, len > buflen ? buflen : len); 2755bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2756c0c050c5SMichael Chan return rc; 2757c0c050c5SMichael Chan } 2758c0c050c5SMichael Chan 2759c0c050c5SMichael Chan static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 2760c0c050c5SMichael Chan u32 length, u8 *data) 2761c0c050c5SMichael Chan { 2762c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2763c0c050c5SMichael Chan int rc; 2764c0c050c5SMichael Chan u8 *buf; 2765c0c050c5SMichael Chan dma_addr_t dma_handle; 2766bbf33d1dSEdwin Peer struct hwrm_nvm_read_input *req; 2767c0c050c5SMichael Chan 2768e0ad8fc5SMichael Chan if (!length) 2769e0ad8fc5SMichael Chan return -EINVAL; 2770e0ad8fc5SMichael Chan 2771bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 2772bbf33d1dSEdwin Peer if (rc) 2773bbf33d1dSEdwin Peer return rc; 2774bbf33d1dSEdwin Peer 2775bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 2776c0c050c5SMichael Chan if (!buf) { 2777bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2778c0c050c5SMichael Chan return -ENOMEM; 2779c0c050c5SMichael Chan } 2780c0c050c5SMichael Chan 2781bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2782bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2783bbf33d1dSEdwin Peer req->offset = cpu_to_le32(offset); 2784bbf33d1dSEdwin Peer req->len = cpu_to_le32(length); 2785bbf33d1dSEdwin Peer 2786bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2787bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2788c0c050c5SMichael Chan if (rc == 0) 2789c0c050c5SMichael Chan memcpy(data, buf, length); 2790bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2791c0c050c5SMichael Chan return rc; 2792c0c050c5SMichael Chan } 2793c0c050c5SMichael Chan 27943ebf6f0aSRob Swindell static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 27953ebf6f0aSRob Swindell u16 ext, u16 *index, u32 *item_length, 27963ebf6f0aSRob Swindell u32 *data_length) 27973ebf6f0aSRob Swindell { 2798bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_output *output; 2799bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_input *req; 28003ebf6f0aSRob Swindell struct bnxt *bp = netdev_priv(dev); 28013ebf6f0aSRob Swindell int rc; 28023ebf6f0aSRob Swindell 2803bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 2804bbf33d1dSEdwin Peer if (rc) 2805bbf33d1dSEdwin Peer return rc; 2806bbf33d1dSEdwin Peer 2807bbf33d1dSEdwin Peer req->enables = 0; 2808bbf33d1dSEdwin Peer req->dir_idx = 0; 2809bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(type); 2810bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(ordinal); 2811bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(ext); 2812bbf33d1dSEdwin Peer req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 2813bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2814bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 28153ebf6f0aSRob Swindell if (rc == 0) { 28163ebf6f0aSRob Swindell if (index) 28173ebf6f0aSRob Swindell *index = le16_to_cpu(output->dir_idx); 28183ebf6f0aSRob Swindell if (item_length) 28193ebf6f0aSRob Swindell *item_length = le32_to_cpu(output->dir_item_length); 28203ebf6f0aSRob Swindell if (data_length) 28213ebf6f0aSRob Swindell *data_length = le32_to_cpu(output->dir_data_length); 28223ebf6f0aSRob Swindell } 2823bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 28243ebf6f0aSRob Swindell return rc; 28253ebf6f0aSRob Swindell } 28263ebf6f0aSRob Swindell 28273ebf6f0aSRob Swindell static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 28283ebf6f0aSRob Swindell { 28293ebf6f0aSRob Swindell char *retval = NULL; 28303ebf6f0aSRob Swindell char *p; 28313ebf6f0aSRob Swindell char *value; 28323ebf6f0aSRob Swindell int field = 0; 28333ebf6f0aSRob Swindell 28343ebf6f0aSRob Swindell if (datalen < 1) 28353ebf6f0aSRob Swindell return NULL; 28363ebf6f0aSRob Swindell /* null-terminate the log data (removing last '\n'): */ 28373ebf6f0aSRob Swindell data[datalen - 1] = 0; 28383ebf6f0aSRob Swindell for (p = data; *p != 0; p++) { 28393ebf6f0aSRob Swindell field = 0; 28403ebf6f0aSRob Swindell retval = NULL; 28413ebf6f0aSRob Swindell while (*p != 0 && *p != '\n') { 28423ebf6f0aSRob Swindell value = p; 28433ebf6f0aSRob Swindell while (*p != 0 && *p != '\t' && *p != '\n') 28443ebf6f0aSRob Swindell p++; 28453ebf6f0aSRob Swindell if (field == desired_field) 28463ebf6f0aSRob Swindell retval = value; 28473ebf6f0aSRob Swindell if (*p != '\t') 28483ebf6f0aSRob Swindell break; 28493ebf6f0aSRob Swindell *p = 0; 28503ebf6f0aSRob Swindell field++; 28513ebf6f0aSRob Swindell p++; 28523ebf6f0aSRob Swindell } 28533ebf6f0aSRob Swindell if (*p == 0) 28543ebf6f0aSRob Swindell break; 28553ebf6f0aSRob Swindell *p = 0; 28563ebf6f0aSRob Swindell } 28573ebf6f0aSRob Swindell return retval; 28583ebf6f0aSRob Swindell } 28593ebf6f0aSRob Swindell 286063185eb3SVikas Gupta int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 28613ebf6f0aSRob Swindell { 2862a60faa60SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 28633ebf6f0aSRob Swindell u16 index = 0; 2864a60faa60SVasundhara Volam char *pkgver; 2865a60faa60SVasundhara Volam u32 pkglen; 2866a60faa60SVasundhara Volam u8 *pkgbuf; 286763185eb3SVikas Gupta int rc; 28683ebf6f0aSRob Swindell 286963185eb3SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 28703ebf6f0aSRob Swindell BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 287163185eb3SVikas Gupta &index, NULL, &pkglen); 287263185eb3SVikas Gupta if (rc) 287363185eb3SVikas Gupta return rc; 28743ebf6f0aSRob Swindell 2875a60faa60SVasundhara Volam pkgbuf = kzalloc(pkglen, GFP_KERNEL); 2876a60faa60SVasundhara Volam if (!pkgbuf) { 2877a60faa60SVasundhara Volam dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 2878a60faa60SVasundhara Volam pkglen); 287963185eb3SVikas Gupta return -ENOMEM; 2880a60faa60SVasundhara Volam } 28813ebf6f0aSRob Swindell 288263185eb3SVikas Gupta rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 288363185eb3SVikas Gupta if (rc) 2884a60faa60SVasundhara Volam goto err; 2885a60faa60SVasundhara Volam 2886a60faa60SVasundhara Volam pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 2887a60faa60SVasundhara Volam pkglen); 288863185eb3SVikas Gupta if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 288963185eb3SVikas Gupta strscpy(ver, pkgver, size); 289063185eb3SVikas Gupta else 289163185eb3SVikas Gupta rc = -ENOENT; 289263185eb3SVikas Gupta 2893a60faa60SVasundhara Volam err: 2894a60faa60SVasundhara Volam kfree(pkgbuf); 289563185eb3SVikas Gupta 289663185eb3SVikas Gupta return rc; 289763185eb3SVikas Gupta } 289863185eb3SVikas Gupta 289963185eb3SVikas Gupta static void bnxt_get_pkgver(struct net_device *dev) 290063185eb3SVikas Gupta { 290163185eb3SVikas Gupta struct bnxt *bp = netdev_priv(dev); 290263185eb3SVikas Gupta char buf[FW_VER_STR_LEN]; 290363185eb3SVikas Gupta int len; 290463185eb3SVikas Gupta 290563185eb3SVikas Gupta if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 290663185eb3SVikas Gupta len = strlen(bp->fw_ver_str); 290763185eb3SVikas Gupta snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 290863185eb3SVikas Gupta "/pkg %s", buf); 290963185eb3SVikas Gupta } 29103ebf6f0aSRob Swindell } 29113ebf6f0aSRob Swindell 2912c0c050c5SMichael Chan static int bnxt_get_eeprom(struct net_device *dev, 2913c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 2914c0c050c5SMichael Chan u8 *data) 2915c0c050c5SMichael Chan { 2916c0c050c5SMichael Chan u32 index; 2917c0c050c5SMichael Chan u32 offset; 2918c0c050c5SMichael Chan 2919c0c050c5SMichael Chan if (eeprom->offset == 0) /* special offset value to get directory */ 2920c0c050c5SMichael Chan return bnxt_get_nvram_directory(dev, eeprom->len, data); 2921c0c050c5SMichael Chan 2922c0c050c5SMichael Chan index = eeprom->offset >> 24; 2923c0c050c5SMichael Chan offset = eeprom->offset & 0xffffff; 2924c0c050c5SMichael Chan 2925c0c050c5SMichael Chan if (index == 0) { 2926c0c050c5SMichael Chan netdev_err(dev, "unsupported index value: %d\n", index); 2927c0c050c5SMichael Chan return -EINVAL; 2928c0c050c5SMichael Chan } 2929c0c050c5SMichael Chan 2930c0c050c5SMichael Chan return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 2931c0c050c5SMichael Chan } 2932c0c050c5SMichael Chan 2933c0c050c5SMichael Chan static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 2934c0c050c5SMichael Chan { 2935bbf33d1dSEdwin Peer struct hwrm_nvm_erase_dir_entry_input *req; 2936c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2937bbf33d1dSEdwin Peer int rc; 2938c0c050c5SMichael Chan 2939bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 2940bbf33d1dSEdwin Peer if (rc) 2941bbf33d1dSEdwin Peer return rc; 2942bbf33d1dSEdwin Peer 2943bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2944bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 2945c0c050c5SMichael Chan } 2946c0c050c5SMichael Chan 2947c0c050c5SMichael Chan static int bnxt_set_eeprom(struct net_device *dev, 2948c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 2949c0c050c5SMichael Chan u8 *data) 2950c0c050c5SMichael Chan { 2951c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2952c0c050c5SMichael Chan u8 index, dir_op; 2953c0c050c5SMichael Chan u16 type, ext, ordinal, attr; 2954c0c050c5SMichael Chan 2955c0c050c5SMichael Chan if (!BNXT_PF(bp)) { 2956c0c050c5SMichael Chan netdev_err(dev, "NVM write not supported from a virtual function\n"); 2957c0c050c5SMichael Chan return -EINVAL; 2958c0c050c5SMichael Chan } 2959c0c050c5SMichael Chan 2960c0c050c5SMichael Chan type = eeprom->magic >> 16; 2961c0c050c5SMichael Chan 2962c0c050c5SMichael Chan if (type == 0xffff) { /* special value for directory operations */ 2963c0c050c5SMichael Chan index = eeprom->magic & 0xff; 2964c0c050c5SMichael Chan dir_op = eeprom->magic >> 8; 2965c0c050c5SMichael Chan if (index == 0) 2966c0c050c5SMichael Chan return -EINVAL; 2967c0c050c5SMichael Chan switch (dir_op) { 2968c0c050c5SMichael Chan case 0x0e: /* erase */ 2969c0c050c5SMichael Chan if (eeprom->offset != ~eeprom->magic) 2970c0c050c5SMichael Chan return -EINVAL; 2971c0c050c5SMichael Chan return bnxt_erase_nvram_directory(dev, index - 1); 2972c0c050c5SMichael Chan default: 2973c0c050c5SMichael Chan return -EINVAL; 2974c0c050c5SMichael Chan } 2975c0c050c5SMichael Chan } 2976c0c050c5SMichael Chan 2977c0c050c5SMichael Chan /* Create or re-write an NVM item: */ 2978ba425800SJason Yan if (bnxt_dir_type_is_executable(type)) 29795ac67d8bSRob Swindell return -EOPNOTSUPP; 2980c0c050c5SMichael Chan ext = eeprom->magic & 0xffff; 2981c0c050c5SMichael Chan ordinal = eeprom->offset >> 16; 2982c0c050c5SMichael Chan attr = eeprom->offset & 0xffff; 2983c0c050c5SMichael Chan 2984bbf33d1dSEdwin Peer return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 2985c0c050c5SMichael Chan eeprom->len); 2986c0c050c5SMichael Chan } 2987c0c050c5SMichael Chan 298872b34f04SMichael Chan static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 298972b34f04SMichael Chan { 299072b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 299172b34f04SMichael Chan struct ethtool_eee *eee = &bp->eee; 299272b34f04SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2993a5390690SMichael Chan u32 advertising; 299472b34f04SMichael Chan int rc = 0; 299572b34f04SMichael Chan 2996c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 299775362a3fSMichael Chan return -EOPNOTSUPP; 299872b34f04SMichael Chan 2999b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 300072b34f04SMichael Chan return -EOPNOTSUPP; 300172b34f04SMichael Chan 3002a5390690SMichael Chan mutex_lock(&bp->link_lock); 3003a5390690SMichael Chan advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 300472b34f04SMichael Chan if (!edata->eee_enabled) 300572b34f04SMichael Chan goto eee_ok; 300672b34f04SMichael Chan 300772b34f04SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 300872b34f04SMichael Chan netdev_warn(dev, "EEE requires autoneg\n"); 3009a5390690SMichael Chan rc = -EINVAL; 3010a5390690SMichael Chan goto eee_exit; 301172b34f04SMichael Chan } 301272b34f04SMichael Chan if (edata->tx_lpi_enabled) { 301372b34f04SMichael Chan if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 301472b34f04SMichael Chan edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 301572b34f04SMichael Chan netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 301672b34f04SMichael Chan bp->lpi_tmr_lo, bp->lpi_tmr_hi); 3017a5390690SMichael Chan rc = -EINVAL; 3018a5390690SMichael Chan goto eee_exit; 301972b34f04SMichael Chan } else if (!bp->lpi_tmr_hi) { 302072b34f04SMichael Chan edata->tx_lpi_timer = eee->tx_lpi_timer; 302172b34f04SMichael Chan } 302272b34f04SMichael Chan } 302372b34f04SMichael Chan if (!edata->advertised) { 302472b34f04SMichael Chan edata->advertised = advertising & eee->supported; 302572b34f04SMichael Chan } else if (edata->advertised & ~advertising) { 302672b34f04SMichael Chan netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 302772b34f04SMichael Chan edata->advertised, advertising); 3028a5390690SMichael Chan rc = -EINVAL; 3029a5390690SMichael Chan goto eee_exit; 303072b34f04SMichael Chan } 303172b34f04SMichael Chan 303272b34f04SMichael Chan eee->advertised = edata->advertised; 303372b34f04SMichael Chan eee->tx_lpi_enabled = edata->tx_lpi_enabled; 303472b34f04SMichael Chan eee->tx_lpi_timer = edata->tx_lpi_timer; 303572b34f04SMichael Chan eee_ok: 303672b34f04SMichael Chan eee->eee_enabled = edata->eee_enabled; 303772b34f04SMichael Chan 303872b34f04SMichael Chan if (netif_running(dev)) 303972b34f04SMichael Chan rc = bnxt_hwrm_set_link_setting(bp, false, true); 304072b34f04SMichael Chan 3041a5390690SMichael Chan eee_exit: 3042a5390690SMichael Chan mutex_unlock(&bp->link_lock); 304372b34f04SMichael Chan return rc; 304472b34f04SMichael Chan } 304572b34f04SMichael Chan 304672b34f04SMichael Chan static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 304772b34f04SMichael Chan { 304872b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 304972b34f04SMichael Chan 3050b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 305172b34f04SMichael Chan return -EOPNOTSUPP; 305272b34f04SMichael Chan 305372b34f04SMichael Chan *edata = bp->eee; 305472b34f04SMichael Chan if (!bp->eee.eee_enabled) { 305572b34f04SMichael Chan /* Preserve tx_lpi_timer so that the last value will be used 305672b34f04SMichael Chan * by default when it is re-enabled. 305772b34f04SMichael Chan */ 305872b34f04SMichael Chan edata->advertised = 0; 305972b34f04SMichael Chan edata->tx_lpi_enabled = 0; 306072b34f04SMichael Chan } 306172b34f04SMichael Chan 306272b34f04SMichael Chan if (!bp->eee.eee_active) 306372b34f04SMichael Chan edata->lp_advertised = 0; 306472b34f04SMichael Chan 306572b34f04SMichael Chan return 0; 306672b34f04SMichael Chan } 306772b34f04SMichael Chan 306842ee18feSAjit Khaparde static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 306942ee18feSAjit Khaparde u16 page_number, u16 start_addr, 307042ee18feSAjit Khaparde u16 data_length, u8 *buf) 307142ee18feSAjit Khaparde { 3072bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_output *output; 3073bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_input *req; 307442ee18feSAjit Khaparde int rc, byte_offset = 0; 307542ee18feSAjit Khaparde 3076bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 3077bbf33d1dSEdwin Peer if (rc) 3078bbf33d1dSEdwin Peer return rc; 3079bbf33d1dSEdwin Peer 3080bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 3081bbf33d1dSEdwin Peer req->i2c_slave_addr = i2c_addr; 3082bbf33d1dSEdwin Peer req->page_number = cpu_to_le16(page_number); 3083bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(bp->pf.port_id); 308442ee18feSAjit Khaparde do { 308542ee18feSAjit Khaparde u16 xfer_size; 308642ee18feSAjit Khaparde 308742ee18feSAjit Khaparde xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 308842ee18feSAjit Khaparde data_length -= xfer_size; 3089bbf33d1dSEdwin Peer req->page_offset = cpu_to_le16(start_addr + byte_offset); 3090bbf33d1dSEdwin Peer req->data_length = xfer_size; 3091bbf33d1dSEdwin Peer req->enables = cpu_to_le32(start_addr + byte_offset ? 309242ee18feSAjit Khaparde PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); 3093bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 309442ee18feSAjit Khaparde if (!rc) 309542ee18feSAjit Khaparde memcpy(buf + byte_offset, output->data, xfer_size); 309642ee18feSAjit Khaparde byte_offset += xfer_size; 309742ee18feSAjit Khaparde } while (!rc && data_length > 0); 3098bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 309942ee18feSAjit Khaparde 310042ee18feSAjit Khaparde return rc; 310142ee18feSAjit Khaparde } 310242ee18feSAjit Khaparde 310342ee18feSAjit Khaparde static int bnxt_get_module_info(struct net_device *dev, 310442ee18feSAjit Khaparde struct ethtool_modinfo *modinfo) 310542ee18feSAjit Khaparde { 31067328a23cSVasundhara Volam u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 310742ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 310842ee18feSAjit Khaparde int rc; 310942ee18feSAjit Khaparde 311042ee18feSAjit Khaparde /* No point in going further if phy status indicates 311142ee18feSAjit Khaparde * module is not inserted or if it is powered down or 311242ee18feSAjit Khaparde * if it is of type 10GBase-T 311342ee18feSAjit Khaparde */ 311442ee18feSAjit Khaparde if (bp->link_info.module_status > 311542ee18feSAjit Khaparde PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 311642ee18feSAjit Khaparde return -EOPNOTSUPP; 311742ee18feSAjit Khaparde 311842ee18feSAjit Khaparde /* This feature is not supported in older firmware versions */ 311942ee18feSAjit Khaparde if (bp->hwrm_spec_code < 0x10202) 312042ee18feSAjit Khaparde return -EOPNOTSUPP; 312142ee18feSAjit Khaparde 31227328a23cSVasundhara Volam rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 31237328a23cSVasundhara Volam SFF_DIAG_SUPPORT_OFFSET + 1, 31247328a23cSVasundhara Volam data); 312542ee18feSAjit Khaparde if (!rc) { 31267328a23cSVasundhara Volam u8 module_id = data[0]; 31277328a23cSVasundhara Volam u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 312842ee18feSAjit Khaparde 312942ee18feSAjit Khaparde switch (module_id) { 313042ee18feSAjit Khaparde case SFF_MODULE_ID_SFP: 313142ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8472; 313242ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 31337328a23cSVasundhara Volam if (!diag_supported) 31347328a23cSVasundhara Volam modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 313542ee18feSAjit Khaparde break; 313642ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP: 313742ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP_PLUS: 313842ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8436; 313942ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 314042ee18feSAjit Khaparde break; 314142ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP28: 314242ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8636; 314342ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 314442ee18feSAjit Khaparde break; 314542ee18feSAjit Khaparde default: 314642ee18feSAjit Khaparde rc = -EOPNOTSUPP; 314742ee18feSAjit Khaparde break; 314842ee18feSAjit Khaparde } 314942ee18feSAjit Khaparde } 315042ee18feSAjit Khaparde return rc; 315142ee18feSAjit Khaparde } 315242ee18feSAjit Khaparde 315342ee18feSAjit Khaparde static int bnxt_get_module_eeprom(struct net_device *dev, 315442ee18feSAjit Khaparde struct ethtool_eeprom *eeprom, 315542ee18feSAjit Khaparde u8 *data) 315642ee18feSAjit Khaparde { 315742ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 315842ee18feSAjit Khaparde u16 start = eeprom->offset, length = eeprom->len; 3159f3ea3119SColin Ian King int rc = 0; 316042ee18feSAjit Khaparde 316142ee18feSAjit Khaparde memset(data, 0, eeprom->len); 316242ee18feSAjit Khaparde 316342ee18feSAjit Khaparde /* Read A0 portion of the EEPROM */ 316442ee18feSAjit Khaparde if (start < ETH_MODULE_SFF_8436_LEN) { 316542ee18feSAjit Khaparde if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 316642ee18feSAjit Khaparde length = ETH_MODULE_SFF_8436_LEN - start; 316742ee18feSAjit Khaparde rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 316842ee18feSAjit Khaparde start, length, data); 316942ee18feSAjit Khaparde if (rc) 317042ee18feSAjit Khaparde return rc; 317142ee18feSAjit Khaparde start += length; 317242ee18feSAjit Khaparde data += length; 317342ee18feSAjit Khaparde length = eeprom->len - length; 317442ee18feSAjit Khaparde } 317542ee18feSAjit Khaparde 317642ee18feSAjit Khaparde /* Read A2 portion of the EEPROM */ 317742ee18feSAjit Khaparde if (length) { 317842ee18feSAjit Khaparde start -= ETH_MODULE_SFF_8436_LEN; 31794260330bSEdwin Peer rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 3180dea521a2SChristophe JAILLET start, length, data); 318142ee18feSAjit Khaparde } 318242ee18feSAjit Khaparde return rc; 318342ee18feSAjit Khaparde } 318442ee18feSAjit Khaparde 3185ae8e98a6SDeepak Khungar static int bnxt_nway_reset(struct net_device *dev) 3186ae8e98a6SDeepak Khungar { 3187ae8e98a6SDeepak Khungar int rc = 0; 3188ae8e98a6SDeepak Khungar 3189ae8e98a6SDeepak Khungar struct bnxt *bp = netdev_priv(dev); 3190ae8e98a6SDeepak Khungar struct bnxt_link_info *link_info = &bp->link_info; 3191ae8e98a6SDeepak Khungar 3192c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 3193ae8e98a6SDeepak Khungar return -EOPNOTSUPP; 3194ae8e98a6SDeepak Khungar 3195ae8e98a6SDeepak Khungar if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 3196ae8e98a6SDeepak Khungar return -EINVAL; 3197ae8e98a6SDeepak Khungar 3198ae8e98a6SDeepak Khungar if (netif_running(dev)) 3199ae8e98a6SDeepak Khungar rc = bnxt_hwrm_set_link_setting(bp, true, false); 3200ae8e98a6SDeepak Khungar 3201ae8e98a6SDeepak Khungar return rc; 3202ae8e98a6SDeepak Khungar } 3203ae8e98a6SDeepak Khungar 32045ad2cbeeSMichael Chan static int bnxt_set_phys_id(struct net_device *dev, 32055ad2cbeeSMichael Chan enum ethtool_phys_id_state state) 32065ad2cbeeSMichael Chan { 3207bbf33d1dSEdwin Peer struct hwrm_port_led_cfg_input *req; 32085ad2cbeeSMichael Chan struct bnxt *bp = netdev_priv(dev); 32095ad2cbeeSMichael Chan struct bnxt_pf_info *pf = &bp->pf; 32105ad2cbeeSMichael Chan struct bnxt_led_cfg *led_cfg; 32115ad2cbeeSMichael Chan u8 led_state; 32125ad2cbeeSMichael Chan __le16 duration; 3213bbf33d1dSEdwin Peer int rc, i; 32145ad2cbeeSMichael Chan 32155ad2cbeeSMichael Chan if (!bp->num_leds || BNXT_VF(bp)) 32165ad2cbeeSMichael Chan return -EOPNOTSUPP; 32175ad2cbeeSMichael Chan 32185ad2cbeeSMichael Chan if (state == ETHTOOL_ID_ACTIVE) { 32195ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 32205ad2cbeeSMichael Chan duration = cpu_to_le16(500); 32215ad2cbeeSMichael Chan } else if (state == ETHTOOL_ID_INACTIVE) { 32225ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 32235ad2cbeeSMichael Chan duration = cpu_to_le16(0); 32245ad2cbeeSMichael Chan } else { 32255ad2cbeeSMichael Chan return -EINVAL; 32265ad2cbeeSMichael Chan } 3227bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 3228bbf33d1dSEdwin Peer if (rc) 3229bbf33d1dSEdwin Peer return rc; 3230bbf33d1dSEdwin Peer 3231bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(pf->port_id); 3232bbf33d1dSEdwin Peer req->num_leds = bp->num_leds; 3233bbf33d1dSEdwin Peer led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 32345ad2cbeeSMichael Chan for (i = 0; i < bp->num_leds; i++, led_cfg++) { 3235bbf33d1dSEdwin Peer req->enables |= BNXT_LED_DFLT_ENABLES(i); 32365ad2cbeeSMichael Chan led_cfg->led_id = bp->leds[i].led_id; 32375ad2cbeeSMichael Chan led_cfg->led_state = led_state; 32385ad2cbeeSMichael Chan led_cfg->led_blink_on = duration; 32395ad2cbeeSMichael Chan led_cfg->led_blink_off = duration; 32405ad2cbeeSMichael Chan led_cfg->led_group_id = bp->leds[i].led_group_id; 32415ad2cbeeSMichael Chan } 3242bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 32435ad2cbeeSMichael Chan } 32445ad2cbeeSMichael Chan 324567fea463SMichael Chan static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 324667fea463SMichael Chan { 3247bbf33d1dSEdwin Peer struct hwrm_selftest_irq_input *req; 3248bbf33d1dSEdwin Peer int rc; 324967fea463SMichael Chan 3250bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 3251bbf33d1dSEdwin Peer if (rc) 3252bbf33d1dSEdwin Peer return rc; 3253bbf33d1dSEdwin Peer 3254bbf33d1dSEdwin Peer req->cmpl_ring = cpu_to_le16(cmpl_ring); 3255bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 325667fea463SMichael Chan } 325767fea463SMichael Chan 325867fea463SMichael Chan static int bnxt_test_irq(struct bnxt *bp) 325967fea463SMichael Chan { 326067fea463SMichael Chan int i; 326167fea463SMichael Chan 326267fea463SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 326367fea463SMichael Chan u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 326467fea463SMichael Chan int rc; 326567fea463SMichael Chan 326667fea463SMichael Chan rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 326767fea463SMichael Chan if (rc) 326867fea463SMichael Chan return rc; 326967fea463SMichael Chan } 327067fea463SMichael Chan return 0; 327167fea463SMichael Chan } 327267fea463SMichael Chan 3273f7dc1ea6SMichael Chan static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 3274f7dc1ea6SMichael Chan { 3275bbf33d1dSEdwin Peer struct hwrm_port_mac_cfg_input *req; 3276bbf33d1dSEdwin Peer int rc; 3277f7dc1ea6SMichael Chan 3278bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 3279bbf33d1dSEdwin Peer if (rc) 3280bbf33d1dSEdwin Peer return rc; 3281f7dc1ea6SMichael Chan 3282bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 3283f7dc1ea6SMichael Chan if (enable) 3284bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 3285f7dc1ea6SMichael Chan else 3286bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 3287bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3288f7dc1ea6SMichael Chan } 3289f7dc1ea6SMichael Chan 329056d37462SVasundhara Volam static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 329156d37462SVasundhara Volam { 3292bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_output *resp; 3293bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_input *req; 329456d37462SVasundhara Volam int rc; 329556d37462SVasundhara Volam 3296bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 3297bbf33d1dSEdwin Peer if (rc) 3298bbf33d1dSEdwin Peer return rc; 3299bbf33d1dSEdwin Peer 3300bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3301bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 330256d37462SVasundhara Volam if (!rc) 330356d37462SVasundhara Volam *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 330456d37462SVasundhara Volam 3305bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 330656d37462SVasundhara Volam return rc; 330756d37462SVasundhara Volam } 330856d37462SVasundhara Volam 330991725d89SMichael Chan static int bnxt_disable_an_for_lpbk(struct bnxt *bp, 331091725d89SMichael Chan struct hwrm_port_phy_cfg_input *req) 331191725d89SMichael Chan { 331291725d89SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 331356d37462SVasundhara Volam u16 fw_advertising; 331491725d89SMichael Chan u16 fw_speed; 331591725d89SMichael Chan int rc; 331691725d89SMichael Chan 33178a60efd1SMichael Chan if (!link_info->autoneg || 3318b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 331991725d89SMichael Chan return 0; 332091725d89SMichael Chan 332156d37462SVasundhara Volam rc = bnxt_query_force_speeds(bp, &fw_advertising); 332256d37462SVasundhara Volam if (rc) 332356d37462SVasundhara Volam return rc; 332456d37462SVasundhara Volam 332591725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 332683d8f5e9SMichael Chan if (bp->link_info.link_up) 332791725d89SMichael Chan fw_speed = bp->link_info.link_speed; 332891725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 332991725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 333091725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 333191725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 333291725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 333391725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 333491725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 333591725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 333691725d89SMichael Chan 333791725d89SMichael Chan req->force_link_speed = cpu_to_le16(fw_speed); 333891725d89SMichael Chan req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 333991725d89SMichael Chan PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 3340bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 334191725d89SMichael Chan req->flags = 0; 334291725d89SMichael Chan req->force_link_speed = cpu_to_le16(0); 334391725d89SMichael Chan return rc; 334491725d89SMichael Chan } 334591725d89SMichael Chan 334655fd0cf3SMichael Chan static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 334791725d89SMichael Chan { 3348bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 3349bbf33d1dSEdwin Peer int rc; 335091725d89SMichael Chan 3351bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 3352bbf33d1dSEdwin Peer if (rc) 3353bbf33d1dSEdwin Peer return rc; 3354bbf33d1dSEdwin Peer 3355bbf33d1dSEdwin Peer /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 3356bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 335791725d89SMichael Chan 335891725d89SMichael Chan if (enable) { 3359bbf33d1dSEdwin Peer bnxt_disable_an_for_lpbk(bp, req); 336055fd0cf3SMichael Chan if (ext) 3361bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 336255fd0cf3SMichael Chan else 3363bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 336491725d89SMichael Chan } else { 3365bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 336691725d89SMichael Chan } 3367bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 3368bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3369bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3370bbf33d1dSEdwin Peer return rc; 337191725d89SMichael Chan } 337291725d89SMichael Chan 3373e44758b7SMichael Chan static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3374f7dc1ea6SMichael Chan u32 raw_cons, int pkt_size) 3375f7dc1ea6SMichael Chan { 3376e44758b7SMichael Chan struct bnxt_napi *bnapi = cpr->bnapi; 3377e44758b7SMichael Chan struct bnxt_rx_ring_info *rxr; 3378f7dc1ea6SMichael Chan struct bnxt_sw_rx_bd *rx_buf; 3379f7dc1ea6SMichael Chan struct rx_cmp *rxcmp; 3380f7dc1ea6SMichael Chan u16 cp_cons, cons; 3381f7dc1ea6SMichael Chan u8 *data; 3382f7dc1ea6SMichael Chan u32 len; 3383f7dc1ea6SMichael Chan int i; 3384f7dc1ea6SMichael Chan 3385e44758b7SMichael Chan rxr = bnapi->rx_ring; 3386f7dc1ea6SMichael Chan cp_cons = RING_CMP(raw_cons); 3387f7dc1ea6SMichael Chan rxcmp = (struct rx_cmp *) 3388f7dc1ea6SMichael Chan &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 3389f7dc1ea6SMichael Chan cons = rxcmp->rx_cmp_opaque; 3390f7dc1ea6SMichael Chan rx_buf = &rxr->rx_buf_ring[cons]; 3391f7dc1ea6SMichael Chan data = rx_buf->data_ptr; 3392f7dc1ea6SMichael Chan len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 3393f7dc1ea6SMichael Chan if (len != pkt_size) 3394f7dc1ea6SMichael Chan return -EIO; 3395f7dc1ea6SMichael Chan i = ETH_ALEN; 3396f7dc1ea6SMichael Chan if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 3397f7dc1ea6SMichael Chan return -EIO; 3398f7dc1ea6SMichael Chan i += ETH_ALEN; 3399f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) { 3400f7dc1ea6SMichael Chan if (data[i] != (u8)(i & 0xff)) 3401f7dc1ea6SMichael Chan return -EIO; 3402f7dc1ea6SMichael Chan } 3403f7dc1ea6SMichael Chan return 0; 3404f7dc1ea6SMichael Chan } 3405f7dc1ea6SMichael Chan 3406e44758b7SMichael Chan static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3407e44758b7SMichael Chan int pkt_size) 3408f7dc1ea6SMichael Chan { 3409f7dc1ea6SMichael Chan struct tx_cmp *txcmp; 3410f7dc1ea6SMichael Chan int rc = -EIO; 3411f7dc1ea6SMichael Chan u32 raw_cons; 3412f7dc1ea6SMichael Chan u32 cons; 3413f7dc1ea6SMichael Chan int i; 3414f7dc1ea6SMichael Chan 3415f7dc1ea6SMichael Chan raw_cons = cpr->cp_raw_cons; 3416f7dc1ea6SMichael Chan for (i = 0; i < 200; i++) { 3417f7dc1ea6SMichael Chan cons = RING_CMP(raw_cons); 3418f7dc1ea6SMichael Chan txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 3419f7dc1ea6SMichael Chan 3420f7dc1ea6SMichael Chan if (!TX_CMP_VALID(txcmp, raw_cons)) { 3421f7dc1ea6SMichael Chan udelay(5); 3422f7dc1ea6SMichael Chan continue; 3423f7dc1ea6SMichael Chan } 3424f7dc1ea6SMichael Chan 3425f7dc1ea6SMichael Chan /* The valid test of the entry must be done first before 3426f7dc1ea6SMichael Chan * reading any further. 3427f7dc1ea6SMichael Chan */ 3428f7dc1ea6SMichael Chan dma_rmb(); 3429f7dc1ea6SMichael Chan if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 3430e44758b7SMichael Chan rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 3431f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3432f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3433f7dc1ea6SMichael Chan break; 3434f7dc1ea6SMichael Chan } 3435f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3436f7dc1ea6SMichael Chan } 3437f7dc1ea6SMichael Chan cpr->cp_raw_cons = raw_cons; 3438f7dc1ea6SMichael Chan return rc; 3439f7dc1ea6SMichael Chan } 3440f7dc1ea6SMichael Chan 3441f7dc1ea6SMichael Chan static int bnxt_run_loopback(struct bnxt *bp) 3442f7dc1ea6SMichael Chan { 3443f7dc1ea6SMichael Chan struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 344484404d5fSMichael Chan struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 3445e44758b7SMichael Chan struct bnxt_cp_ring_info *cpr; 3446f7dc1ea6SMichael Chan int pkt_size, i = 0; 3447f7dc1ea6SMichael Chan struct sk_buff *skb; 3448f7dc1ea6SMichael Chan dma_addr_t map; 3449f7dc1ea6SMichael Chan u8 *data; 3450f7dc1ea6SMichael Chan int rc; 3451f7dc1ea6SMichael Chan 345284404d5fSMichael Chan cpr = &rxr->bnapi->cp_ring; 345384404d5fSMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 345484404d5fSMichael Chan cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 3455f7dc1ea6SMichael Chan pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 3456f7dc1ea6SMichael Chan skb = netdev_alloc_skb(bp->dev, pkt_size); 3457f7dc1ea6SMichael Chan if (!skb) 3458f7dc1ea6SMichael Chan return -ENOMEM; 3459f7dc1ea6SMichael Chan data = skb_put(skb, pkt_size); 3460f7dc1ea6SMichael Chan eth_broadcast_addr(data); 3461f7dc1ea6SMichael Chan i += ETH_ALEN; 3462f7dc1ea6SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3463f7dc1ea6SMichael Chan i += ETH_ALEN; 3464f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) 3465f7dc1ea6SMichael Chan data[i] = (u8)(i & 0xff); 3466f7dc1ea6SMichael Chan 3467f7dc1ea6SMichael Chan map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 3468df70303dSChristophe JAILLET DMA_TO_DEVICE); 3469f7dc1ea6SMichael Chan if (dma_mapping_error(&bp->pdev->dev, map)) { 3470f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3471f7dc1ea6SMichael Chan return -EIO; 3472f7dc1ea6SMichael Chan } 3473c1ba92a8SMichael Chan bnxt_xmit_bd(bp, txr, map, pkt_size); 3474f7dc1ea6SMichael Chan 3475f7dc1ea6SMichael Chan /* Sync BD data before updating doorbell */ 3476f7dc1ea6SMichael Chan wmb(); 3477f7dc1ea6SMichael Chan 3478697197e5SMichael Chan bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 3479e44758b7SMichael Chan rc = bnxt_poll_loopback(bp, cpr, pkt_size); 3480f7dc1ea6SMichael Chan 3481df70303dSChristophe JAILLET dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 3482f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3483f7dc1ea6SMichael Chan return rc; 3484f7dc1ea6SMichael Chan } 3485f7dc1ea6SMichael Chan 3486eb513658SMichael Chan static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 3487eb513658SMichael Chan { 3488bbf33d1dSEdwin Peer struct hwrm_selftest_exec_output *resp; 3489bbf33d1dSEdwin Peer struct hwrm_selftest_exec_input *req; 3490eb513658SMichael Chan int rc; 3491eb513658SMichael Chan 3492bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 3493bbf33d1dSEdwin Peer if (rc) 3494bbf33d1dSEdwin Peer return rc; 3495bbf33d1dSEdwin Peer 3496bbf33d1dSEdwin Peer hwrm_req_timeout(bp, req, bp->test_info->timeout); 3497bbf33d1dSEdwin Peer req->flags = test_mask; 3498bbf33d1dSEdwin Peer 3499bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3500bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3501eb513658SMichael Chan *test_results = resp->test_success; 3502bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3503eb513658SMichael Chan return rc; 3504eb513658SMichael Chan } 3505eb513658SMichael Chan 350655fd0cf3SMichael Chan #define BNXT_DRV_TESTS 4 3507f7dc1ea6SMichael Chan #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 350891725d89SMichael Chan #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 350955fd0cf3SMichael Chan #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 351055fd0cf3SMichael Chan #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 3511eb513658SMichael Chan 3512eb513658SMichael Chan static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 3513eb513658SMichael Chan u64 *buf) 3514eb513658SMichael Chan { 3515eb513658SMichael Chan struct bnxt *bp = netdev_priv(dev); 351655fd0cf3SMichael Chan bool do_ext_lpbk = false; 3517eb513658SMichael Chan bool offline = false; 3518eb513658SMichael Chan u8 test_results = 0; 3519eb513658SMichael Chan u8 test_mask = 0; 3520d27e2ca1SMichael Chan int rc = 0, i; 3521eb513658SMichael Chan 35226896cb35SVasundhara Volam if (!bp->num_tests || !BNXT_PF(bp)) 3523eb513658SMichael Chan return; 3524eb513658SMichael Chan memset(buf, 0, sizeof(u64) * bp->num_tests); 3525eb513658SMichael Chan if (!netif_running(dev)) { 3526eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3527eb513658SMichael Chan return; 3528eb513658SMichael Chan } 3529eb513658SMichael Chan 353055fd0cf3SMichael Chan if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 3531b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 353255fd0cf3SMichael Chan do_ext_lpbk = true; 353355fd0cf3SMichael Chan 3534eb513658SMichael Chan if (etest->flags & ETH_TEST_FL_OFFLINE) { 35356896cb35SVasundhara Volam if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 3536eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 35376896cb35SVasundhara Volam netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 3538eb513658SMichael Chan return; 3539eb513658SMichael Chan } 3540eb513658SMichael Chan offline = true; 3541eb513658SMichael Chan } 3542eb513658SMichael Chan 3543eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3544eb513658SMichael Chan u8 bit_val = 1 << i; 3545eb513658SMichael Chan 3546eb513658SMichael Chan if (!(bp->test_info->offline_mask & bit_val)) 3547eb513658SMichael Chan test_mask |= bit_val; 3548eb513658SMichael Chan else if (offline) 3549eb513658SMichael Chan test_mask |= bit_val; 3550eb513658SMichael Chan } 3551eb513658SMichael Chan if (!offline) { 3552eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3553eb513658SMichael Chan } else { 3554eb513658SMichael Chan rc = bnxt_close_nic(bp, false, false); 3555eb513658SMichael Chan if (rc) 3556eb513658SMichael Chan return; 3557eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3558f7dc1ea6SMichael Chan 3559f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 1; 3560f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, true); 3561f7dc1ea6SMichael Chan msleep(250); 3562f7dc1ea6SMichael Chan rc = bnxt_half_open_nic(bp); 3563f7dc1ea6SMichael Chan if (rc) { 3564f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 3565f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3566f7dc1ea6SMichael Chan return; 3567f7dc1ea6SMichael Chan } 3568f7dc1ea6SMichael Chan if (bnxt_run_loopback(bp)) 3569f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3570f7dc1ea6SMichael Chan else 3571f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 0; 3572f7dc1ea6SMichael Chan 3573f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 357455fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, false); 357591725d89SMichael Chan msleep(1000); 357691725d89SMichael Chan if (bnxt_run_loopback(bp)) { 357791725d89SMichael Chan buf[BNXT_PHYLPBK_TEST_IDX] = 1; 357891725d89SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 357991725d89SMichael Chan } 358055fd0cf3SMichael Chan if (do_ext_lpbk) { 358155fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 358255fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, true); 358355fd0cf3SMichael Chan msleep(1000); 358455fd0cf3SMichael Chan if (bnxt_run_loopback(bp)) { 358555fd0cf3SMichael Chan buf[BNXT_EXTLPBK_TEST_IDX] = 1; 358655fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 358755fd0cf3SMichael Chan } 358855fd0cf3SMichael Chan } 358955fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, false, false); 359091725d89SMichael Chan bnxt_half_close_nic(bp); 3591d27e2ca1SMichael Chan rc = bnxt_open_nic(bp, false, true); 3592eb513658SMichael Chan } 3593d27e2ca1SMichael Chan if (rc || bnxt_test_irq(bp)) { 359467fea463SMichael Chan buf[BNXT_IRQ_TEST_IDX] = 1; 359567fea463SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 359667fea463SMichael Chan } 3597eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3598eb513658SMichael Chan u8 bit_val = 1 << i; 3599eb513658SMichael Chan 3600eb513658SMichael Chan if ((test_mask & bit_val) && !(test_results & bit_val)) { 3601eb513658SMichael Chan buf[i] = 1; 3602eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3603eb513658SMichael Chan } 3604eb513658SMichael Chan } 3605eb513658SMichael Chan } 3606eb513658SMichael Chan 360749f7972fSVasundhara Volam static int bnxt_reset(struct net_device *dev, u32 *flags) 360849f7972fSVasundhara Volam { 360949f7972fSVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36108cec0940SEdwin Peer bool reload = false; 36117a13240eSEdwin Peer u32 req = *flags; 36127a13240eSEdwin Peer 36137a13240eSEdwin Peer if (!req) 36147a13240eSEdwin Peer return -EINVAL; 361549f7972fSVasundhara Volam 361649f7972fSVasundhara Volam if (!BNXT_PF(bp)) { 361749f7972fSVasundhara Volam netdev_err(dev, "Reset is not supported from a VF\n"); 361849f7972fSVasundhara Volam return -EOPNOTSUPP; 361949f7972fSVasundhara Volam } 362049f7972fSVasundhara Volam 36210a3f4e4fSVasundhara Volam if (pci_vfs_assigned(bp->pdev) && 36220a3f4e4fSVasundhara Volam !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 362349f7972fSVasundhara Volam netdev_err(dev, 362449f7972fSVasundhara Volam "Reset not allowed when VFs are assigned to VMs\n"); 362549f7972fSVasundhara Volam return -EBUSY; 362649f7972fSVasundhara Volam } 362749f7972fSVasundhara Volam 36287a13240eSEdwin Peer if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 362949f7972fSVasundhara Volam /* This feature is not supported in older firmware versions */ 36307a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 36317a13240eSEdwin Peer if (!bnxt_firmware_reset_chip(dev)) { 36327a13240eSEdwin Peer netdev_info(dev, "Firmware reset request successful.\n"); 36330a3f4e4fSVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 36348cec0940SEdwin Peer reload = true; 36357a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_CHIP; 36362373d8d6SScott Branden } 36377a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_CHIP) { 36387a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 36397a13240eSEdwin Peer } 36407a13240eSEdwin Peer } 36417a13240eSEdwin Peer 36427a13240eSEdwin Peer if (req & BNXT_FW_RESET_AP) { 36436502ad59SScott Branden /* This feature is not supported in older firmware versions */ 36447a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 36457a13240eSEdwin Peer if (!bnxt_firmware_reset_ap(dev)) { 36467a13240eSEdwin Peer netdev_info(dev, "Reset application processor successful.\n"); 36478cec0940SEdwin Peer reload = true; 36487a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_AP; 36492373d8d6SScott Branden } 36507a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_AP) { 36517a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 36527a13240eSEdwin Peer } 365349f7972fSVasundhara Volam } 365449f7972fSVasundhara Volam 36558cec0940SEdwin Peer if (reload) 36568cec0940SEdwin Peer netdev_info(dev, "Reload driver to complete reset\n"); 36578cec0940SEdwin Peer 36587a13240eSEdwin Peer return 0; 365949f7972fSVasundhara Volam } 366049f7972fSVasundhara Volam 36610b0eacf3SVasundhara Volam static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 36620b0eacf3SVasundhara Volam { 36630b0eacf3SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36640b0eacf3SVasundhara Volam 36650b0eacf3SVasundhara Volam if (dump->flag > BNXT_DUMP_CRASH) { 36660b0eacf3SVasundhara Volam netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 36670b0eacf3SVasundhara Volam return -EINVAL; 36680b0eacf3SVasundhara Volam } 36690b0eacf3SVasundhara Volam 36700b0eacf3SVasundhara Volam if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 36710b0eacf3SVasundhara Volam netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 36720b0eacf3SVasundhara Volam return -EOPNOTSUPP; 36730b0eacf3SVasundhara Volam } 36740b0eacf3SVasundhara Volam 36750b0eacf3SVasundhara Volam bp->dump_flag = dump->flag; 36760b0eacf3SVasundhara Volam return 0; 36770b0eacf3SVasundhara Volam } 36780b0eacf3SVasundhara Volam 36796c5657d0SVasundhara Volam static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 36806c5657d0SVasundhara Volam { 36816c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 36826c5657d0SVasundhara Volam 36836c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 36846c5657d0SVasundhara Volam return -EOPNOTSUPP; 36856c5657d0SVasundhara Volam 36866c5657d0SVasundhara Volam dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 36876c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_min_8b << 16 | 36886c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_bld_8b << 8 | 36896c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_rsvd_8b; 36906c5657d0SVasundhara Volam 36910b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 36929a575c8cSEdwin Peer dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 36930b0eacf3SVasundhara Volam return 0; 36946c5657d0SVasundhara Volam } 36956c5657d0SVasundhara Volam 36966c5657d0SVasundhara Volam static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 36976c5657d0SVasundhara Volam void *buf) 36986c5657d0SVasundhara Volam { 36996c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37006c5657d0SVasundhara Volam 37016c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 37026c5657d0SVasundhara Volam return -EOPNOTSUPP; 37036c5657d0SVasundhara Volam 37046c5657d0SVasundhara Volam memset(buf, 0, dump->len); 37056c5657d0SVasundhara Volam 37060b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 37079a575c8cSEdwin Peer return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 37080b0eacf3SVasundhara Volam } 37090b0eacf3SVasundhara Volam 3710118612d5SMichael Chan static int bnxt_get_ts_info(struct net_device *dev, 3711118612d5SMichael Chan struct ethtool_ts_info *info) 3712118612d5SMichael Chan { 3713118612d5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3714118612d5SMichael Chan struct bnxt_ptp_cfg *ptp; 3715118612d5SMichael Chan 3716118612d5SMichael Chan ptp = bp->ptp_cfg; 3717118612d5SMichael Chan info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 3718118612d5SMichael Chan SOF_TIMESTAMPING_RX_SOFTWARE | 3719118612d5SMichael Chan SOF_TIMESTAMPING_SOFTWARE; 3720118612d5SMichael Chan 3721118612d5SMichael Chan info->phc_index = -1; 3722118612d5SMichael Chan if (!ptp) 3723118612d5SMichael Chan return 0; 3724118612d5SMichael Chan 3725118612d5SMichael Chan info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 3726118612d5SMichael Chan SOF_TIMESTAMPING_RX_HARDWARE | 3727118612d5SMichael Chan SOF_TIMESTAMPING_RAW_HARDWARE; 3728118612d5SMichael Chan if (ptp->ptp_clock) 3729118612d5SMichael Chan info->phc_index = ptp_clock_index(ptp->ptp_clock); 3730118612d5SMichael Chan 3731118612d5SMichael Chan info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 3732118612d5SMichael Chan 3733118612d5SMichael Chan info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 3734118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 3735118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 3736118612d5SMichael Chan return 0; 3737118612d5SMichael Chan } 3738118612d5SMichael Chan 3739eb513658SMichael Chan void bnxt_ethtool_init(struct bnxt *bp) 3740eb513658SMichael Chan { 3741bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_output *resp; 3742bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_input *req; 3743eb513658SMichael Chan struct bnxt_test_info *test_info; 3744431aa1ebSMichael Chan struct net_device *dev = bp->dev; 3745eb513658SMichael Chan int i, rc; 3746eb513658SMichael Chan 3747691aa620SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 3748a60faa60SVasundhara Volam bnxt_get_pkgver(dev); 3749431aa1ebSMichael Chan 3750ba642ab7SMichael Chan bp->num_tests = 0; 37516896cb35SVasundhara Volam if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 3752eb513658SMichael Chan return; 3753eb513658SMichael Chan 3754bbf33d1dSEdwin Peer test_info = bp->test_info; 3755bbf33d1dSEdwin Peer if (!test_info) { 3756bbf33d1dSEdwin Peer test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 3757bbf33d1dSEdwin Peer if (!test_info) 3758bbf33d1dSEdwin Peer return; 3759bbf33d1dSEdwin Peer bp->test_info = test_info; 3760bbf33d1dSEdwin Peer } 3761bbf33d1dSEdwin Peer 3762bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 3763bbf33d1dSEdwin Peer return; 3764bbf33d1dSEdwin Peer 3765bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3766bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 3767eb513658SMichael Chan if (rc) 3768eb513658SMichael Chan goto ethtool_init_exit; 3769eb513658SMichael Chan 3770eb513658SMichael Chan bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 3771eb513658SMichael Chan if (bp->num_tests > BNXT_MAX_TEST) 3772eb513658SMichael Chan bp->num_tests = BNXT_MAX_TEST; 3773eb513658SMichael Chan 3774eb513658SMichael Chan test_info->offline_mask = resp->offline_tests; 3775eb513658SMichael Chan test_info->timeout = le16_to_cpu(resp->test_timeout); 3776eb513658SMichael Chan if (!test_info->timeout) 3777eb513658SMichael Chan test_info->timeout = HWRM_CMD_TIMEOUT; 3778eb513658SMichael Chan for (i = 0; i < bp->num_tests; i++) { 3779eb513658SMichael Chan char *str = test_info->string[i]; 3780eb513658SMichael Chan char *fw_str = resp->test0_name + i * 32; 3781eb513658SMichael Chan 3782f7dc1ea6SMichael Chan if (i == BNXT_MACLPBK_TEST_IDX) { 3783f7dc1ea6SMichael Chan strcpy(str, "Mac loopback test (offline)"); 378491725d89SMichael Chan } else if (i == BNXT_PHYLPBK_TEST_IDX) { 378591725d89SMichael Chan strcpy(str, "Phy loopback test (offline)"); 378655fd0cf3SMichael Chan } else if (i == BNXT_EXTLPBK_TEST_IDX) { 378755fd0cf3SMichael Chan strcpy(str, "Ext loopback test (offline)"); 378867fea463SMichael Chan } else if (i == BNXT_IRQ_TEST_IDX) { 378967fea463SMichael Chan strcpy(str, "Interrupt_test (offline)"); 3790f7dc1ea6SMichael Chan } else { 3791eb513658SMichael Chan strlcpy(str, fw_str, ETH_GSTRING_LEN); 3792eb513658SMichael Chan strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); 3793eb513658SMichael Chan if (test_info->offline_mask & (1 << i)) 3794eb513658SMichael Chan strncat(str, " (offline)", 3795eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3796eb513658SMichael Chan else 3797eb513658SMichael Chan strncat(str, " (online)", 3798eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3799eb513658SMichael Chan } 3800f7dc1ea6SMichael Chan } 3801eb513658SMichael Chan 3802eb513658SMichael Chan ethtool_init_exit: 3803bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3804eb513658SMichael Chan } 3805eb513658SMichael Chan 3806782bc00aSJakub Kicinski static void bnxt_get_eth_phy_stats(struct net_device *dev, 3807782bc00aSJakub Kicinski struct ethtool_eth_phy_stats *phy_stats) 3808782bc00aSJakub Kicinski { 3809782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3810782bc00aSJakub Kicinski u64 *rx; 3811782bc00aSJakub Kicinski 3812782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 3813782bc00aSJakub Kicinski return; 3814782bc00aSJakub Kicinski 3815782bc00aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 3816782bc00aSJakub Kicinski phy_stats->SymbolErrorDuringCarrier = 3817782bc00aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 3818782bc00aSJakub Kicinski } 3819782bc00aSJakub Kicinski 3820782bc00aSJakub Kicinski static void bnxt_get_eth_mac_stats(struct net_device *dev, 3821782bc00aSJakub Kicinski struct ethtool_eth_mac_stats *mac_stats) 3822782bc00aSJakub Kicinski { 3823782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3824782bc00aSJakub Kicinski u64 *rx, *tx; 3825782bc00aSJakub Kicinski 3826782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3827782bc00aSJakub Kicinski return; 3828782bc00aSJakub Kicinski 3829782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3830782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3831782bc00aSJakub Kicinski 3832782bc00aSJakub Kicinski mac_stats->FramesReceivedOK = 3833782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 3834782bc00aSJakub Kicinski mac_stats->FramesTransmittedOK = 3835782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 383637434782SJakub Kicinski mac_stats->FrameCheckSequenceErrors = 383737434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 383837434782SJakub Kicinski mac_stats->AlignmentErrors = 383937434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 384037434782SJakub Kicinski mac_stats->OutOfRangeLengthField = 384137434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 3842782bc00aSJakub Kicinski } 3843782bc00aSJakub Kicinski 3844782bc00aSJakub Kicinski static void bnxt_get_eth_ctrl_stats(struct net_device *dev, 3845782bc00aSJakub Kicinski struct ethtool_eth_ctrl_stats *ctrl_stats) 3846782bc00aSJakub Kicinski { 3847782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3848782bc00aSJakub Kicinski u64 *rx; 3849782bc00aSJakub Kicinski 3850782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3851782bc00aSJakub Kicinski return; 3852782bc00aSJakub Kicinski 3853782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3854782bc00aSJakub Kicinski ctrl_stats->MACControlFramesReceived = 3855782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 3856782bc00aSJakub Kicinski } 3857782bc00aSJakub Kicinski 3858782bc00aSJakub Kicinski static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 3859782bc00aSJakub Kicinski { 0, 64 }, 3860782bc00aSJakub Kicinski { 65, 127 }, 3861782bc00aSJakub Kicinski { 128, 255 }, 3862782bc00aSJakub Kicinski { 256, 511 }, 3863782bc00aSJakub Kicinski { 512, 1023 }, 3864782bc00aSJakub Kicinski { 1024, 1518 }, 3865782bc00aSJakub Kicinski { 1519, 2047 }, 3866782bc00aSJakub Kicinski { 2048, 4095 }, 3867782bc00aSJakub Kicinski { 4096, 9216 }, 3868782bc00aSJakub Kicinski { 9217, 16383 }, 3869782bc00aSJakub Kicinski {} 3870782bc00aSJakub Kicinski }; 3871782bc00aSJakub Kicinski 3872782bc00aSJakub Kicinski static void bnxt_get_rmon_stats(struct net_device *dev, 3873782bc00aSJakub Kicinski struct ethtool_rmon_stats *rmon_stats, 3874782bc00aSJakub Kicinski const struct ethtool_rmon_hist_range **ranges) 3875782bc00aSJakub Kicinski { 3876782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3877782bc00aSJakub Kicinski u64 *rx, *tx; 3878782bc00aSJakub Kicinski 3879782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 3880782bc00aSJakub Kicinski return; 3881782bc00aSJakub Kicinski 3882782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 3883782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 3884782bc00aSJakub Kicinski 3885782bc00aSJakub Kicinski rmon_stats->jabbers = 3886782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 3887782bc00aSJakub Kicinski rmon_stats->oversize_pkts = 3888782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 3889782bc00aSJakub Kicinski rmon_stats->undersize_pkts = 3890782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 3891782bc00aSJakub Kicinski 3892782bc00aSJakub Kicinski rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 3893782bc00aSJakub Kicinski rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 3894782bc00aSJakub Kicinski rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 3895782bc00aSJakub Kicinski rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 3896782bc00aSJakub Kicinski rmon_stats->hist[4] = 3897782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 3898782bc00aSJakub Kicinski rmon_stats->hist[5] = 3899782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 3900782bc00aSJakub Kicinski rmon_stats->hist[6] = 3901782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 3902782bc00aSJakub Kicinski rmon_stats->hist[7] = 3903782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 3904782bc00aSJakub Kicinski rmon_stats->hist[8] = 3905782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 3906782bc00aSJakub Kicinski rmon_stats->hist[9] = 3907782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 3908782bc00aSJakub Kicinski 3909782bc00aSJakub Kicinski rmon_stats->hist_tx[0] = 3910782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 3911782bc00aSJakub Kicinski rmon_stats->hist_tx[1] = 3912782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 3913782bc00aSJakub Kicinski rmon_stats->hist_tx[2] = 3914782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 3915782bc00aSJakub Kicinski rmon_stats->hist_tx[3] = 3916782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 3917782bc00aSJakub Kicinski rmon_stats->hist_tx[4] = 3918782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 3919782bc00aSJakub Kicinski rmon_stats->hist_tx[5] = 3920782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 3921782bc00aSJakub Kicinski rmon_stats->hist_tx[6] = 3922782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 3923782bc00aSJakub Kicinski rmon_stats->hist_tx[7] = 3924782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 3925782bc00aSJakub Kicinski rmon_stats->hist_tx[8] = 3926782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 3927782bc00aSJakub Kicinski rmon_stats->hist_tx[9] = 3928782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 3929782bc00aSJakub Kicinski 3930782bc00aSJakub Kicinski *ranges = bnxt_rmon_ranges; 3931782bc00aSJakub Kicinski } 3932782bc00aSJakub Kicinski 3933eb513658SMichael Chan void bnxt_ethtool_free(struct bnxt *bp) 3934eb513658SMichael Chan { 3935eb513658SMichael Chan kfree(bp->test_info); 3936eb513658SMichael Chan bp->test_info = NULL; 3937eb513658SMichael Chan } 3938eb513658SMichael Chan 3939c0c050c5SMichael Chan const struct ethtool_ops bnxt_ethtool_ops = { 3940f704d243SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 3941f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES | 3942f704d243SJakub Kicinski ETHTOOL_COALESCE_USECS_IRQ | 3943f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 3944f704d243SJakub Kicinski ETHTOOL_COALESCE_STATS_BLOCK_USECS | 39453fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 39463fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_CQE, 394700c04a92SMichael Chan .get_link_ksettings = bnxt_get_link_ksettings, 394800c04a92SMichael Chan .set_link_ksettings = bnxt_set_link_ksettings, 3949c9ca5c3aSJakub Kicinski .get_fec_stats = bnxt_get_fec_stats, 39508b277589SMichael Chan .get_fecparam = bnxt_get_fecparam, 3951ccd6a9dcSMichael Chan .set_fecparam = bnxt_set_fecparam, 3952423cffcfSJakub Kicinski .get_pause_stats = bnxt_get_pause_stats, 3953c0c050c5SMichael Chan .get_pauseparam = bnxt_get_pauseparam, 3954c0c050c5SMichael Chan .set_pauseparam = bnxt_set_pauseparam, 3955c0c050c5SMichael Chan .get_drvinfo = bnxt_get_drvinfo, 3956b5d600b0SVasundhara Volam .get_regs_len = bnxt_get_regs_len, 3957b5d600b0SVasundhara Volam .get_regs = bnxt_get_regs, 39588e202366SMichael Chan .get_wol = bnxt_get_wol, 39595282db6cSMichael Chan .set_wol = bnxt_set_wol, 3960c0c050c5SMichael Chan .get_coalesce = bnxt_get_coalesce, 3961c0c050c5SMichael Chan .set_coalesce = bnxt_set_coalesce, 3962c0c050c5SMichael Chan .get_msglevel = bnxt_get_msglevel, 3963c0c050c5SMichael Chan .set_msglevel = bnxt_set_msglevel, 3964c0c050c5SMichael Chan .get_sset_count = bnxt_get_sset_count, 3965c0c050c5SMichael Chan .get_strings = bnxt_get_strings, 3966c0c050c5SMichael Chan .get_ethtool_stats = bnxt_get_ethtool_stats, 3967c0c050c5SMichael Chan .set_ringparam = bnxt_set_ringparam, 3968c0c050c5SMichael Chan .get_ringparam = bnxt_get_ringparam, 3969c0c050c5SMichael Chan .get_channels = bnxt_get_channels, 3970c0c050c5SMichael Chan .set_channels = bnxt_set_channels, 3971c0c050c5SMichael Chan .get_rxnfc = bnxt_get_rxnfc, 3972a011952aSMichael Chan .set_rxnfc = bnxt_set_rxnfc, 3973c0c050c5SMichael Chan .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 3974c0c050c5SMichael Chan .get_rxfh_key_size = bnxt_get_rxfh_key_size, 3975c0c050c5SMichael Chan .get_rxfh = bnxt_get_rxfh, 3976bd3191b5SMichael Chan .set_rxfh = bnxt_set_rxfh, 3977c0c050c5SMichael Chan .flash_device = bnxt_flash_device, 3978c0c050c5SMichael Chan .get_eeprom_len = bnxt_get_eeprom_len, 3979c0c050c5SMichael Chan .get_eeprom = bnxt_get_eeprom, 3980c0c050c5SMichael Chan .set_eeprom = bnxt_set_eeprom, 3981c0c050c5SMichael Chan .get_link = bnxt_get_link, 398272b34f04SMichael Chan .get_eee = bnxt_get_eee, 398372b34f04SMichael Chan .set_eee = bnxt_set_eee, 398442ee18feSAjit Khaparde .get_module_info = bnxt_get_module_info, 398542ee18feSAjit Khaparde .get_module_eeprom = bnxt_get_module_eeprom, 39865ad2cbeeSMichael Chan .nway_reset = bnxt_nway_reset, 39875ad2cbeeSMichael Chan .set_phys_id = bnxt_set_phys_id, 3988eb513658SMichael Chan .self_test = bnxt_self_test, 3989118612d5SMichael Chan .get_ts_info = bnxt_get_ts_info, 399049f7972fSVasundhara Volam .reset = bnxt_reset, 39910b0eacf3SVasundhara Volam .set_dump = bnxt_set_dump, 39926c5657d0SVasundhara Volam .get_dump_flag = bnxt_get_dump_flag, 39936c5657d0SVasundhara Volam .get_dump_data = bnxt_get_dump_data, 3994782bc00aSJakub Kicinski .get_eth_phy_stats = bnxt_get_eth_phy_stats, 3995782bc00aSJakub Kicinski .get_eth_mac_stats = bnxt_get_eth_mac_stats, 3996782bc00aSJakub Kicinski .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 3997782bc00aSJakub Kicinski .get_rmon_stats = bnxt_get_rmon_stats, 3998c0c050c5SMichael Chan }; 3999