1c0c050c5SMichael Chan /* Broadcom NetXtreme-C/E network driver. 2c0c050c5SMichael Chan * 311f15ed3SMichael Chan * Copyright (c) 2014-2016 Broadcom Corporation 48e202366SMichael Chan * Copyright (c) 2016-2017 Broadcom Limited 5c0c050c5SMichael Chan * 6c0c050c5SMichael Chan * This program is free software; you can redistribute it and/or modify 7c0c050c5SMichael Chan * it under the terms of the GNU General Public License as published by 8c0c050c5SMichael Chan * the Free Software Foundation. 9c0c050c5SMichael Chan */ 10c0c050c5SMichael Chan 113ebf6f0aSRob Swindell #include <linux/ctype.h> 128ddc9aaaSMichael Chan #include <linux/stringify.h> 13c0c050c5SMichael Chan #include <linux/ethtool.h> 14b370517eSJakub Kicinski #include <linux/ethtool_netlink.h> 158b277589SMichael Chan #include <linux/linkmode.h> 16c0c050c5SMichael Chan #include <linux/interrupt.h> 17c0c050c5SMichael Chan #include <linux/pci.h> 18c0c050c5SMichael Chan #include <linux/etherdevice.h> 19c0c050c5SMichael Chan #include <linux/crc32.h> 20c0c050c5SMichael Chan #include <linux/firmware.h> 216c5657d0SVasundhara Volam #include <linux/utsname.h> 226c5657d0SVasundhara Volam #include <linux/time.h> 23118612d5SMichael Chan #include <linux/ptp_clock_kernel.h> 24118612d5SMichael Chan #include <linux/net_tstamp.h> 25118612d5SMichael Chan #include <linux/timecounter.h> 26ab0bed4bSKalesh AP #include <net/netlink.h> 27c0c050c5SMichael Chan #include "bnxt_hsi.h" 28c0c050c5SMichael Chan #include "bnxt.h" 293c8c20dbSEdwin Peer #include "bnxt_hwrm.h" 306758f937SMichael Chan #include "bnxt_ulp.h" 31f7dc1ea6SMichael Chan #include "bnxt_xdp.h" 32118612d5SMichael Chan #include "bnxt_ptp.h" 33c0c050c5SMichael Chan #include "bnxt_ethtool.h" 34c0c050c5SMichael Chan #include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ 35c0c050c5SMichael Chan #include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ 366c5657d0SVasundhara Volam #include "bnxt_coredump.h" 37c0c050c5SMichael Chan 38ab0bed4bSKalesh AP #define BNXT_NVM_ERR_MSG(dev, extack, msg) \ 39ab0bed4bSKalesh AP do { \ 40ab0bed4bSKalesh AP if (extack) \ 41ab0bed4bSKalesh AP NL_SET_ERR_MSG_MOD(extack, msg); \ 42ab0bed4bSKalesh AP netdev_err(dev, "%s\n", msg); \ 43ab0bed4bSKalesh AP } while (0) 44ab0bed4bSKalesh AP 45c0c050c5SMichael Chan static u32 bnxt_get_msglevel(struct net_device *dev) 46c0c050c5SMichael Chan { 47c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 48c0c050c5SMichael Chan 49c0c050c5SMichael Chan return bp->msg_enable; 50c0c050c5SMichael Chan } 51c0c050c5SMichael Chan 52c0c050c5SMichael Chan static void bnxt_set_msglevel(struct net_device *dev, u32 value) 53c0c050c5SMichael Chan { 54c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 55c0c050c5SMichael Chan 56c0c050c5SMichael Chan bp->msg_enable = value; 57c0c050c5SMichael Chan } 58c0c050c5SMichael Chan 59c0c050c5SMichael Chan static int bnxt_get_coalesce(struct net_device *dev, 60f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 61f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 62f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 63c0c050c5SMichael Chan { 64c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 6518775aa8SMichael Chan struct bnxt_coal *hw_coal; 6618775aa8SMichael Chan u16 mult; 67c0c050c5SMichael Chan 68c0c050c5SMichael Chan memset(coal, 0, sizeof(*coal)); 69c0c050c5SMichael Chan 706a8788f2SAndy Gospodarek coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; 716a8788f2SAndy Gospodarek 7218775aa8SMichael Chan hw_coal = &bp->rx_coal; 7318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 7418775aa8SMichael Chan coal->rx_coalesce_usecs = hw_coal->coal_ticks; 7518775aa8SMichael Chan coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; 7618775aa8SMichael Chan coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 7718775aa8SMichael Chan coal->rx_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_rx = true; 81c0c050c5SMichael Chan 8218775aa8SMichael Chan hw_coal = &bp->tx_coal; 8318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 8418775aa8SMichael Chan coal->tx_coalesce_usecs = hw_coal->coal_ticks; 8518775aa8SMichael Chan coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; 8618775aa8SMichael Chan coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; 8718775aa8SMichael Chan coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; 883fcbdbd5SMichael Chan if (hw_coal->flags & 893fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) 903fcbdbd5SMichael Chan kernel_coal->use_cqe_mode_tx = true; 91dfc9c94aSMichael Chan 9251f30785SMichael Chan coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; 9351f30785SMichael Chan 94c0c050c5SMichael Chan return 0; 95c0c050c5SMichael Chan } 96c0c050c5SMichael Chan 97c0c050c5SMichael Chan static int bnxt_set_coalesce(struct net_device *dev, 98f3ccfda1SYufeng Mo struct ethtool_coalesce *coal, 99f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 100f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 101c0c050c5SMichael Chan { 102c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 10351f30785SMichael Chan bool update_stats = false; 10418775aa8SMichael Chan struct bnxt_coal *hw_coal; 105c0c050c5SMichael Chan int rc = 0; 10618775aa8SMichael Chan u16 mult; 107c0c050c5SMichael Chan 1086a8788f2SAndy Gospodarek if (coal->use_adaptive_rx_coalesce) { 1096a8788f2SAndy Gospodarek bp->flags |= BNXT_FLAG_DIM; 1106a8788f2SAndy Gospodarek } else { 1116a8788f2SAndy Gospodarek if (bp->flags & BNXT_FLAG_DIM) { 1126a8788f2SAndy Gospodarek bp->flags &= ~(BNXT_FLAG_DIM); 1136a8788f2SAndy Gospodarek goto reset_coalesce; 1146a8788f2SAndy Gospodarek } 1156a8788f2SAndy Gospodarek } 1166a8788f2SAndy Gospodarek 1173fcbdbd5SMichael Chan if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && 1183fcbdbd5SMichael Chan !(bp->coal_cap.cmpl_params & 1193fcbdbd5SMichael Chan RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) 1203fcbdbd5SMichael Chan return -EOPNOTSUPP; 1213fcbdbd5SMichael Chan 12218775aa8SMichael Chan hw_coal = &bp->rx_coal; 12318775aa8SMichael Chan mult = hw_coal->bufs_per_record; 12418775aa8SMichael Chan hw_coal->coal_ticks = coal->rx_coalesce_usecs; 12518775aa8SMichael Chan hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; 12618775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; 12718775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; 1283fcbdbd5SMichael Chan hw_coal->flags &= 1293fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1303fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_rx) 1313fcbdbd5SMichael Chan hw_coal->flags |= 1323fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 133c0c050c5SMichael Chan 134de4a10efSAndy Gospodarek hw_coal = &bp->tx_coal; 13518775aa8SMichael Chan mult = hw_coal->bufs_per_record; 13618775aa8SMichael Chan hw_coal->coal_ticks = coal->tx_coalesce_usecs; 13718775aa8SMichael Chan hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; 13818775aa8SMichael Chan hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; 13918775aa8SMichael Chan hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; 1403fcbdbd5SMichael Chan hw_coal->flags &= 1413fcbdbd5SMichael Chan ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 1423fcbdbd5SMichael Chan if (kernel_coal->use_cqe_mode_tx) 1433fcbdbd5SMichael Chan hw_coal->flags |= 1443fcbdbd5SMichael Chan RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; 145dfc9c94aSMichael Chan 14651f30785SMichael Chan if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { 14751f30785SMichael Chan u32 stats_ticks = coal->stats_block_coalesce_usecs; 14851f30785SMichael Chan 149adcc331eSMichael Chan /* Allow 0, which means disable. */ 150adcc331eSMichael Chan if (stats_ticks) 15151f30785SMichael Chan stats_ticks = clamp_t(u32, stats_ticks, 15251f30785SMichael Chan BNXT_MIN_STATS_COAL_TICKS, 15351f30785SMichael Chan BNXT_MAX_STATS_COAL_TICKS); 15451f30785SMichael Chan stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); 15551f30785SMichael Chan bp->stats_coal_ticks = stats_ticks; 156e795892eSMichael Chan if (bp->stats_coal_ticks) 157e795892eSMichael Chan bp->current_interval = 158e795892eSMichael Chan bp->stats_coal_ticks * HZ / 1000000; 159e795892eSMichael Chan else 160e795892eSMichael Chan bp->current_interval = BNXT_TIMER_INTERVAL; 16151f30785SMichael Chan update_stats = true; 16251f30785SMichael Chan } 16351f30785SMichael Chan 1646a8788f2SAndy Gospodarek reset_coalesce: 1656d81ea37SMichael Chan if (test_bit(BNXT_STATE_OPEN, &bp->state)) { 16651f30785SMichael Chan if (update_stats) { 16751f30785SMichael Chan rc = bnxt_close_nic(bp, true, false); 16851f30785SMichael Chan if (!rc) 16951f30785SMichael Chan rc = bnxt_open_nic(bp, true, false); 17051f30785SMichael Chan } else { 171c0c050c5SMichael Chan rc = bnxt_hwrm_set_coal(bp); 17251f30785SMichael Chan } 17351f30785SMichael Chan } 174c0c050c5SMichael Chan 175c0c050c5SMichael Chan return rc; 176c0c050c5SMichael Chan } 177c0c050c5SMichael Chan 1783316d509SMichael Chan static const char * const bnxt_ring_rx_stats_str[] = { 179ee79566eSMichael Chan "rx_ucast_packets", 180ee79566eSMichael Chan "rx_mcast_packets", 181ee79566eSMichael Chan "rx_bcast_packets", 182ee79566eSMichael Chan "rx_discards", 183bfc6e5fbSMichael Chan "rx_errors", 184ee79566eSMichael Chan "rx_ucast_bytes", 185ee79566eSMichael Chan "rx_mcast_bytes", 186ee79566eSMichael Chan "rx_bcast_bytes", 1873316d509SMichael Chan }; 1883316d509SMichael Chan 1893316d509SMichael Chan static const char * const bnxt_ring_tx_stats_str[] = { 190ee79566eSMichael Chan "tx_ucast_packets", 191ee79566eSMichael Chan "tx_mcast_packets", 192ee79566eSMichael Chan "tx_bcast_packets", 193bfc6e5fbSMichael Chan "tx_errors", 194ee79566eSMichael Chan "tx_discards", 195ee79566eSMichael Chan "tx_ucast_bytes", 196ee79566eSMichael Chan "tx_mcast_bytes", 197ee79566eSMichael Chan "tx_bcast_bytes", 198ee79566eSMichael Chan }; 199ee79566eSMichael Chan 200ee79566eSMichael Chan static const char * const bnxt_ring_tpa_stats_str[] = { 201ee79566eSMichael Chan "tpa_packets", 202ee79566eSMichael Chan "tpa_bytes", 203ee79566eSMichael Chan "tpa_events", 204ee79566eSMichael Chan "tpa_aborts", 205ee79566eSMichael Chan }; 206ee79566eSMichael Chan 20778e7b866SMichael Chan static const char * const bnxt_ring_tpa2_stats_str[] = { 20878e7b866SMichael Chan "rx_tpa_eligible_pkt", 20978e7b866SMichael Chan "rx_tpa_eligible_bytes", 21078e7b866SMichael Chan "rx_tpa_pkt", 21178e7b866SMichael Chan "rx_tpa_bytes", 21278e7b866SMichael Chan "rx_tpa_errors", 2139d6b648cSMichael Chan "rx_tpa_events", 21478e7b866SMichael Chan }; 21578e7b866SMichael Chan 2169d8b5f05SMichael Chan static const char * const bnxt_rx_sw_stats_str[] = { 217ee79566eSMichael Chan "rx_l4_csum_errors", 2188a27d4b9SMichael Chan "rx_resets", 21919b3751fSMichael Chan "rx_buf_errors", 2209d8b5f05SMichael Chan }; 2219d8b5f05SMichael Chan 2229d8b5f05SMichael Chan static const char * const bnxt_cmn_sw_stats_str[] = { 223ee79566eSMichael Chan "missed_irqs", 224ee79566eSMichael Chan }; 225c0c050c5SMichael Chan 2268ddc9aaaSMichael Chan #define BNXT_RX_STATS_ENTRY(counter) \ 2278ddc9aaaSMichael Chan { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } 2288ddc9aaaSMichael Chan 2298ddc9aaaSMichael Chan #define BNXT_TX_STATS_ENTRY(counter) \ 2308ddc9aaaSMichael Chan { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } 2318ddc9aaaSMichael Chan 23200db3cbaSVasundhara Volam #define BNXT_RX_STATS_EXT_ENTRY(counter) \ 23300db3cbaSVasundhara Volam { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } 23400db3cbaSVasundhara Volam 23536e53349SMichael Chan #define BNXT_TX_STATS_EXT_ENTRY(counter) \ 23636e53349SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } 23736e53349SMichael Chan 23836e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ 23936e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ 24036e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) 24136e53349SMichael Chan 24236e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ 24336e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ 24436e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) 24536e53349SMichael Chan 24636e53349SMichael Chan #define BNXT_RX_STATS_EXT_PFC_ENTRIES \ 24736e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ 24836e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ 24936e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ 25036e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ 25136e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ 25236e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ 25336e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ 25436e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRY(7) 25536e53349SMichael Chan 25636e53349SMichael Chan #define BNXT_TX_STATS_EXT_PFC_ENTRIES \ 25736e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ 25836e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ 25936e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ 26036e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ 26136e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ 26236e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ 26336e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ 26436e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRY(7) 26536e53349SMichael Chan 26636e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ 26736e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ 26836e53349SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) 26936e53349SMichael Chan 27036e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ 27136e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ 27236e53349SMichael Chan BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) 27336e53349SMichael Chan 27436e53349SMichael Chan #define BNXT_RX_STATS_EXT_COS_ENTRIES \ 27536e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(0), \ 27636e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(1), \ 27736e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(2), \ 27836e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(3), \ 27936e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(4), \ 28036e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(5), \ 28136e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(6), \ 28236e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRY(7) \ 28336e53349SMichael Chan 28436e53349SMichael Chan #define BNXT_TX_STATS_EXT_COS_ENTRIES \ 28536e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(0), \ 28636e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(1), \ 28736e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(2), \ 28836e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(3), \ 28936e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(4), \ 29036e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(5), \ 29136e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(6), \ 29236e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRY(7) \ 29336e53349SMichael Chan 2942792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ 2952792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ 2962792b5b9SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) 2972792b5b9SMichael Chan 2982792b5b9SMichael Chan #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ 2992792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ 3002792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ 3012792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ 3022792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ 3032792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ 3042792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ 3052792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ 3062792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) 3072792b5b9SMichael Chan 308e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ 309e37fed79SMichael Chan { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ 310e37fed79SMichael Chan __stringify(counter##_pri##n) } 311e37fed79SMichael Chan 312e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ 313e37fed79SMichael Chan { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ 314e37fed79SMichael Chan __stringify(counter##_pri##n) } 315e37fed79SMichael Chan 316e37fed79SMichael Chan #define BNXT_RX_STATS_PRI_ENTRIES(counter) \ 317e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ 318e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ 319e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ 320e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ 321e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ 322e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ 323e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ 324e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRY(counter, 7) 325e37fed79SMichael Chan 326e37fed79SMichael Chan #define BNXT_TX_STATS_PRI_ENTRIES(counter) \ 327e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ 328e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ 329e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ 330e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ 331e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ 332e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ 333e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ 334e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRY(counter, 7) 335e37fed79SMichael Chan 33620c1d28eSVasundhara Volam enum { 33720c1d28eSVasundhara Volam RX_TOTAL_DISCARDS, 33820c1d28eSVasundhara Volam TX_TOTAL_DISCARDS, 33940bedf7cSJakub Kicinski RX_NETPOLL_DISCARDS, 34020c1d28eSVasundhara Volam }; 34120c1d28eSVasundhara Volam 34220c1d28eSVasundhara Volam static struct { 34320c1d28eSVasundhara Volam u64 counter; 34420c1d28eSVasundhara Volam char string[ETH_GSTRING_LEN]; 34520c1d28eSVasundhara Volam } bnxt_sw_func_stats[] = { 34620c1d28eSVasundhara Volam {0, "rx_total_discard_pkts"}, 34720c1d28eSVasundhara Volam {0, "tx_total_discard_pkts"}, 34840bedf7cSJakub Kicinski {0, "rx_total_netpoll_discards"}, 34920c1d28eSVasundhara Volam }; 35020c1d28eSVasundhara Volam 3513316d509SMichael Chan #define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) 3523316d509SMichael Chan #define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) 3533316d509SMichael Chan #define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) 3543316d509SMichael Chan #define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) 3553316d509SMichael Chan 3568ddc9aaaSMichael Chan static const struct { 3578ddc9aaaSMichael Chan long offset; 3588ddc9aaaSMichael Chan char string[ETH_GSTRING_LEN]; 3598ddc9aaaSMichael Chan } bnxt_port_stats_arr[] = { 3608ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_64b_frames), 3618ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), 3628ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), 3638ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), 3648ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), 3656fc92c33SMichael Chan BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), 3668ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), 3678ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), 3688ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), 3698ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), 3708ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), 3718ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_total_frames), 3728ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ucast_frames), 3738ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mcast_frames), 3748ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bcast_frames), 3758ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), 3768ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ctrl_frames), 3778ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pause_frames), 3788ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_frames), 3798ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_align_err_frames), 3808ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), 3818ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_jbr_frames), 3828ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), 3838ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_tagged_frames), 3848ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), 3858ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_good_frames), 386c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), 387c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), 388c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), 389c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), 390c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), 391c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), 392c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), 393c77192f2SMichael Chan BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), 3948ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_undrsz_frames), 3958ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), 3968ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), 3978ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_bytes), 3988ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_bytes), 3998ddc9aaaSMichael Chan BNXT_RX_STATS_ENTRY(rx_runt_frames), 400699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_discard), 401699efed0SVasundhara Volam BNXT_RX_STATS_ENTRY(rx_stat_err), 4028ddc9aaaSMichael Chan 4038ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_64b_frames), 4048ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), 4058ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), 4068ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), 4078ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), 4086fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), 4098ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), 4106fc92c33SMichael Chan BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), 4118ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), 4128ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), 4138ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), 4148ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_good_frames), 4158ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_frames), 4168ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_ucast_frames), 4178ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_mcast_frames), 4188ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bcast_frames), 4198ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pause_frames), 4208ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_frames), 4218ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_jabber_frames), 4228ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), 4238ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_err), 4248ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_fifo_underruns), 425c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), 426c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), 427c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), 428c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), 429c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), 430c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), 431c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), 432c77192f2SMichael Chan BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), 4338ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), 4348ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), 4358ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_total_collisions), 4368ddc9aaaSMichael Chan BNXT_TX_STATS_ENTRY(tx_bytes), 437699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_xthol_frames), 438699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_discard), 439699efed0SVasundhara Volam BNXT_TX_STATS_ENTRY(tx_stat_error), 4408ddc9aaaSMichael Chan }; 4418ddc9aaaSMichael Chan 44200db3cbaSVasundhara Volam static const struct { 44300db3cbaSVasundhara Volam long offset; 44400db3cbaSVasundhara Volam char string[ETH_GSTRING_LEN]; 44500db3cbaSVasundhara Volam } bnxt_port_stats_ext_arr[] = { 44600db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(link_down_events), 44700db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), 44800db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), 44900db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), 45000db3cbaSVasundhara Volam BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), 45136e53349SMichael Chan BNXT_RX_STATS_EXT_COS_ENTRIES, 45236e53349SMichael Chan BNXT_RX_STATS_EXT_PFC_ENTRIES, 4534a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_bits), 4544a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), 4554a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), 4564a50ddc2SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), 4572792b5b9SMichael Chan BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, 45821e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), 45921e70778SMichael Chan BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), 46036e53349SMichael Chan }; 46136e53349SMichael Chan 46236e53349SMichael Chan static const struct { 46336e53349SMichael Chan long offset; 46436e53349SMichael Chan char string[ETH_GSTRING_LEN]; 46536e53349SMichael Chan } bnxt_tx_port_stats_ext_arr[] = { 46636e53349SMichael Chan BNXT_TX_STATS_EXT_COS_ENTRIES, 46736e53349SMichael Chan BNXT_TX_STATS_EXT_PFC_ENTRIES, 46800db3cbaSVasundhara Volam }; 46900db3cbaSVasundhara Volam 470e37fed79SMichael Chan static const struct { 471e37fed79SMichael Chan long base_off; 472e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 473e37fed79SMichael Chan } bnxt_rx_bytes_pri_arr[] = { 474e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), 475e37fed79SMichael Chan }; 476e37fed79SMichael Chan 477e37fed79SMichael Chan static const struct { 478e37fed79SMichael Chan long base_off; 479e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 480e37fed79SMichael Chan } bnxt_rx_pkts_pri_arr[] = { 481e37fed79SMichael Chan BNXT_RX_STATS_PRI_ENTRIES(rx_packets), 482e37fed79SMichael Chan }; 483e37fed79SMichael Chan 484e37fed79SMichael Chan static const struct { 485e37fed79SMichael Chan long base_off; 486e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 487e37fed79SMichael Chan } bnxt_tx_bytes_pri_arr[] = { 488e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), 489e37fed79SMichael Chan }; 490e37fed79SMichael Chan 491e37fed79SMichael Chan static const struct { 492e37fed79SMichael Chan long base_off; 493e37fed79SMichael Chan char string[ETH_GSTRING_LEN]; 494e37fed79SMichael Chan } bnxt_tx_pkts_pri_arr[] = { 495e37fed79SMichael Chan BNXT_TX_STATS_PRI_ENTRIES(tx_packets), 496e37fed79SMichael Chan }; 497e37fed79SMichael Chan 49820c1d28eSVasundhara Volam #define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats) 4998ddc9aaaSMichael Chan #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) 500e37fed79SMichael Chan #define BNXT_NUM_STATS_PRI \ 501e37fed79SMichael Chan (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ 502e37fed79SMichael Chan ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ 503e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ 504e37fed79SMichael Chan ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) 5058ddc9aaaSMichael Chan 50678e7b866SMichael Chan static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) 50778e7b866SMichael Chan { 50878e7b866SMichael Chan if (BNXT_SUPPORTS_TPA(bp)) { 5099d6b648cSMichael Chan if (bp->max_tpa_v2) { 5109d6b648cSMichael Chan if (BNXT_CHIP_P5_THOR(bp)) 5119d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5; 5129d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS_P5_SR2; 5139d6b648cSMichael Chan } 5149d6b648cSMichael Chan return BNXT_NUM_TPA_RING_STATS; 51578e7b866SMichael Chan } 51678e7b866SMichael Chan return 0; 51778e7b866SMichael Chan } 51878e7b866SMichael Chan 519ee79566eSMichael Chan static int bnxt_get_num_ring_stats(struct bnxt *bp) 520ee79566eSMichael Chan { 5213316d509SMichael Chan int rx, tx, cmn; 522ee79566eSMichael Chan 5233316d509SMichael Chan rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + 52478e7b866SMichael Chan bnxt_get_num_tpa_ring_stats(bp); 5253316d509SMichael Chan tx = NUM_RING_TX_HW_STATS; 5263316d509SMichael Chan cmn = NUM_RING_CMN_SW_STATS; 527125592fbSRajesh Ravi return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings + 528125592fbSRajesh Ravi cmn * bp->cp_nr_rings; 529ee79566eSMichael Chan } 530ee79566eSMichael Chan 5315c8227d0SMichael Chan static int bnxt_get_num_stats(struct bnxt *bp) 532c0c050c5SMichael Chan { 533ee79566eSMichael Chan int num_stats = bnxt_get_num_ring_stats(bp); 5348ddc9aaaSMichael Chan 53520c1d28eSVasundhara Volam num_stats += BNXT_NUM_SW_FUNC_STATS; 53620c1d28eSVasundhara Volam 5378ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) 5388ddc9aaaSMichael Chan num_stats += BNXT_NUM_PORT_STATS; 5398ddc9aaaSMichael Chan 540e37fed79SMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 54136e53349SMichael Chan num_stats += bp->fw_rx_stats_ext_size + 54236e53349SMichael Chan bp->fw_tx_stats_ext_size; 543e37fed79SMichael Chan if (bp->pri2cos_valid) 544e37fed79SMichael Chan num_stats += BNXT_NUM_STATS_PRI; 545e37fed79SMichael Chan } 54600db3cbaSVasundhara Volam 5478ddc9aaaSMichael Chan return num_stats; 5488ddc9aaaSMichael Chan } 5495c8227d0SMichael Chan 5505c8227d0SMichael Chan static int bnxt_get_sset_count(struct net_device *dev, int sset) 5515c8227d0SMichael Chan { 5525c8227d0SMichael Chan struct bnxt *bp = netdev_priv(dev); 5535c8227d0SMichael Chan 5545c8227d0SMichael Chan switch (sset) { 5555c8227d0SMichael Chan case ETH_SS_STATS: 5565c8227d0SMichael Chan return bnxt_get_num_stats(bp); 557eb513658SMichael Chan case ETH_SS_TEST: 558eb513658SMichael Chan if (!bp->num_tests) 559eb513658SMichael Chan return -EOPNOTSUPP; 560eb513658SMichael Chan return bp->num_tests; 561c0c050c5SMichael Chan default: 562c0c050c5SMichael Chan return -EOPNOTSUPP; 563c0c050c5SMichael Chan } 564c0c050c5SMichael Chan } 565c0c050c5SMichael Chan 566125592fbSRajesh Ravi static bool is_rx_ring(struct bnxt *bp, int ring_num) 567125592fbSRajesh Ravi { 568125592fbSRajesh Ravi return ring_num < bp->rx_nr_rings; 569125592fbSRajesh Ravi } 570125592fbSRajesh Ravi 571125592fbSRajesh Ravi static bool is_tx_ring(struct bnxt *bp, int ring_num) 572125592fbSRajesh Ravi { 573125592fbSRajesh Ravi int tx_base = 0; 574125592fbSRajesh Ravi 575125592fbSRajesh Ravi if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) 576125592fbSRajesh Ravi tx_base = bp->rx_nr_rings; 577125592fbSRajesh Ravi 578125592fbSRajesh Ravi if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) 579125592fbSRajesh Ravi return true; 580125592fbSRajesh Ravi return false; 581125592fbSRajesh Ravi } 582125592fbSRajesh Ravi 583c0c050c5SMichael Chan static void bnxt_get_ethtool_stats(struct net_device *dev, 584c0c050c5SMichael Chan struct ethtool_stats *stats, u64 *buf) 585c0c050c5SMichael Chan { 586c0c050c5SMichael Chan u32 i, j = 0; 587c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 588125592fbSRajesh Ravi u32 tpa_stats; 589c0c050c5SMichael Chan 590fd3ab1c7SMichael Chan if (!bp->bnapi) { 591ee79566eSMichael Chan j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS; 592fd3ab1c7SMichael Chan goto skip_ring_stats; 593fd3ab1c7SMichael Chan } 594c0c050c5SMichael Chan 59520c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) 59620c1d28eSVasundhara Volam bnxt_sw_func_stats[i].counter = 0; 59720c1d28eSVasundhara Volam 598125592fbSRajesh Ravi tpa_stats = bnxt_get_num_tpa_ring_stats(bp); 599c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 600c0c050c5SMichael Chan struct bnxt_napi *bnapi = bp->bnapi[i]; 601c0c050c5SMichael Chan struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; 602a0c30621SMichael Chan u64 *sw_stats = cpr->stats.sw_stats; 6039d8b5f05SMichael Chan u64 *sw; 604c0c050c5SMichael Chan int k; 605c0c050c5SMichael Chan 606125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 607125592fbSRajesh Ravi for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) 608a0c30621SMichael Chan buf[j] = sw_stats[k]; 609125592fbSRajesh Ravi } 610125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 611125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS; 612125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 613125592fbSRajesh Ravi j++, k++) 614a0c30621SMichael Chan buf[j] = sw_stats[k]; 615125592fbSRajesh Ravi } 616125592fbSRajesh Ravi if (!tpa_stats || !is_rx_ring(bp, i)) 617125592fbSRajesh Ravi goto skip_tpa_ring_stats; 618125592fbSRajesh Ravi 619125592fbSRajesh Ravi k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; 620125592fbSRajesh Ravi for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + 621125592fbSRajesh Ravi tpa_stats; j++, k++) 622a0c30621SMichael Chan buf[j] = sw_stats[k]; 6239d8b5f05SMichael Chan 624125592fbSRajesh Ravi skip_tpa_ring_stats: 6259d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.rx; 626125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 6273316d509SMichael Chan for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) 6289d8b5f05SMichael Chan buf[j] = sw[k]; 629125592fbSRajesh Ravi } 6309d8b5f05SMichael Chan 6319d8b5f05SMichael Chan sw = (u64 *)&cpr->sw_stats.cmn; 6323316d509SMichael Chan for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) 6339d8b5f05SMichael Chan buf[j] = sw[k]; 63420c1d28eSVasundhara Volam 63520c1d28eSVasundhara Volam bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += 636a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts); 63720c1d28eSVasundhara Volam bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter += 638a0c30621SMichael Chan BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts); 63940bedf7cSJakub Kicinski bnxt_sw_func_stats[RX_NETPOLL_DISCARDS].counter += 64040bedf7cSJakub Kicinski cpr->sw_stats.rx.rx_netpoll_discards; 641c0c050c5SMichael Chan } 64220c1d28eSVasundhara Volam 64320c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++) 64420c1d28eSVasundhara Volam buf[j] = bnxt_sw_func_stats[i].counter; 64520c1d28eSVasundhara Volam 646fd3ab1c7SMichael Chan skip_ring_stats: 6478ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 648a0c30621SMichael Chan u64 *port_stats = bp->port_stats.sw_stats; 6498ddc9aaaSMichael Chan 650a0c30621SMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) 651a0c30621SMichael Chan buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); 6528ddc9aaaSMichael Chan } 65300db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 654a0c30621SMichael Chan u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; 655a0c30621SMichael Chan u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; 65600db3cbaSVasundhara Volam 65736e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) { 658a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + 659a0c30621SMichael Chan bnxt_port_stats_ext_arr[i].offset); 66000db3cbaSVasundhara Volam } 66136e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) { 662a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + 663a0c30621SMichael Chan bnxt_tx_port_stats_ext_arr[i].offset); 66436e53349SMichael Chan } 665e37fed79SMichael Chan if (bp->pri2cos_valid) { 666e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 667e37fed79SMichael Chan long n = bnxt_rx_bytes_pri_arr[i].base_off + 668a24ec322SMichael Chan bp->pri2cos_idx[i]; 669e37fed79SMichael Chan 670a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 671e37fed79SMichael Chan } 672e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 673e37fed79SMichael Chan long n = bnxt_rx_pkts_pri_arr[i].base_off + 674a24ec322SMichael Chan bp->pri2cos_idx[i]; 675e37fed79SMichael Chan 676a0c30621SMichael Chan buf[j] = *(rx_port_stats_ext + n); 677e37fed79SMichael Chan } 678e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 679e37fed79SMichael Chan long n = bnxt_tx_bytes_pri_arr[i].base_off + 680a24ec322SMichael Chan bp->pri2cos_idx[i]; 681e37fed79SMichael Chan 682a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 683e37fed79SMichael Chan } 684e37fed79SMichael Chan for (i = 0; i < 8; i++, j++) { 685e37fed79SMichael Chan long n = bnxt_tx_pkts_pri_arr[i].base_off + 686a24ec322SMichael Chan bp->pri2cos_idx[i]; 687e37fed79SMichael Chan 688a0c30621SMichael Chan buf[j] = *(tx_port_stats_ext + n); 689e37fed79SMichael Chan } 690e37fed79SMichael Chan } 69100db3cbaSVasundhara Volam } 692c0c050c5SMichael Chan } 693c0c050c5SMichael Chan 694c0c050c5SMichael Chan static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 695c0c050c5SMichael Chan { 696c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 69778e7b866SMichael Chan static const char * const *str; 698ee79566eSMichael Chan u32 i, j, num_str; 699c0c050c5SMichael Chan 700c0c050c5SMichael Chan switch (stringset) { 701c0c050c5SMichael Chan case ETH_SS_STATS: 702c0c050c5SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 703125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 7043316d509SMichael Chan num_str = NUM_RING_RX_HW_STATS; 705ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 706ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 7073316d509SMichael Chan bnxt_ring_rx_stats_str[j]); 708c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 709ee79566eSMichael Chan } 710125592fbSRajesh Ravi } 711125592fbSRajesh Ravi if (is_tx_ring(bp, i)) { 7123316d509SMichael Chan num_str = NUM_RING_TX_HW_STATS; 7133316d509SMichael Chan for (j = 0; j < num_str; j++) { 7143316d509SMichael Chan sprintf(buf, "[%d]: %s", i, 7153316d509SMichael Chan bnxt_ring_tx_stats_str[j]); 7163316d509SMichael Chan buf += ETH_GSTRING_LEN; 7173316d509SMichael Chan } 718125592fbSRajesh Ravi } 7193316d509SMichael Chan num_str = bnxt_get_num_tpa_ring_stats(bp); 720125592fbSRajesh Ravi if (!num_str || !is_rx_ring(bp, i)) 721ee79566eSMichael Chan goto skip_tpa_stats; 722ee79566eSMichael Chan 7233316d509SMichael Chan if (bp->max_tpa_v2) 72478e7b866SMichael Chan str = bnxt_ring_tpa2_stats_str; 7253316d509SMichael Chan else 72678e7b866SMichael Chan str = bnxt_ring_tpa_stats_str; 7273316d509SMichael Chan 728ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 72978e7b866SMichael Chan sprintf(buf, "[%d]: %s", i, str[j]); 730c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 731ee79566eSMichael Chan } 732ee79566eSMichael Chan skip_tpa_stats: 733125592fbSRajesh Ravi if (is_rx_ring(bp, i)) { 7343316d509SMichael Chan num_str = NUM_RING_RX_SW_STATS; 735ee79566eSMichael Chan for (j = 0; j < num_str; j++) { 736ee79566eSMichael Chan sprintf(buf, "[%d]: %s", i, 7379d8b5f05SMichael Chan bnxt_rx_sw_stats_str[j]); 7389d8b5f05SMichael Chan buf += ETH_GSTRING_LEN; 7399d8b5f05SMichael Chan } 740125592fbSRajesh Ravi } 7413316d509SMichael Chan num_str = NUM_RING_CMN_SW_STATS; 7429d8b5f05SMichael Chan for (j = 0; j < num_str; j++) { 7439d8b5f05SMichael Chan sprintf(buf, "[%d]: %s", i, 7449d8b5f05SMichael Chan bnxt_cmn_sw_stats_str[j]); 745c0c050c5SMichael Chan buf += ETH_GSTRING_LEN; 746ee79566eSMichael Chan } 747c0c050c5SMichael Chan } 74820c1d28eSVasundhara Volam for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) { 74920c1d28eSVasundhara Volam strcpy(buf, bnxt_sw_func_stats[i].string); 75020c1d28eSVasundhara Volam buf += ETH_GSTRING_LEN; 75120c1d28eSVasundhara Volam } 75220c1d28eSVasundhara Volam 7538ddc9aaaSMichael Chan if (bp->flags & BNXT_FLAG_PORT_STATS) { 7548ddc9aaaSMichael Chan for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { 7558ddc9aaaSMichael Chan strcpy(buf, bnxt_port_stats_arr[i].string); 7568ddc9aaaSMichael Chan buf += ETH_GSTRING_LEN; 7578ddc9aaaSMichael Chan } 7588ddc9aaaSMichael Chan } 75900db3cbaSVasundhara Volam if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { 76036e53349SMichael Chan for (i = 0; i < bp->fw_rx_stats_ext_size; i++) { 76100db3cbaSVasundhara Volam strcpy(buf, bnxt_port_stats_ext_arr[i].string); 76200db3cbaSVasundhara Volam buf += ETH_GSTRING_LEN; 76300db3cbaSVasundhara Volam } 76436e53349SMichael Chan for (i = 0; i < bp->fw_tx_stats_ext_size; i++) { 76536e53349SMichael Chan strcpy(buf, 76636e53349SMichael Chan bnxt_tx_port_stats_ext_arr[i].string); 76736e53349SMichael Chan buf += ETH_GSTRING_LEN; 76836e53349SMichael Chan } 769e37fed79SMichael Chan if (bp->pri2cos_valid) { 770e37fed79SMichael Chan for (i = 0; i < 8; i++) { 771e37fed79SMichael Chan strcpy(buf, 772e37fed79SMichael Chan bnxt_rx_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_rx_pkts_pri_arr[i].string); 778e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 779e37fed79SMichael Chan } 780e37fed79SMichael Chan for (i = 0; i < 8; i++) { 781e37fed79SMichael Chan strcpy(buf, 782e37fed79SMichael Chan bnxt_tx_bytes_pri_arr[i].string); 783e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 784e37fed79SMichael Chan } 785e37fed79SMichael Chan for (i = 0; i < 8; i++) { 786e37fed79SMichael Chan strcpy(buf, 787e37fed79SMichael Chan bnxt_tx_pkts_pri_arr[i].string); 788e37fed79SMichael Chan buf += ETH_GSTRING_LEN; 789e37fed79SMichael Chan } 790e37fed79SMichael Chan } 79100db3cbaSVasundhara Volam } 792c0c050c5SMichael Chan break; 793eb513658SMichael Chan case ETH_SS_TEST: 794eb513658SMichael Chan if (bp->num_tests) 795eb513658SMichael Chan memcpy(buf, bp->test_info->string, 796eb513658SMichael Chan bp->num_tests * ETH_GSTRING_LEN); 797eb513658SMichael Chan break; 798c0c050c5SMichael Chan default: 799c0c050c5SMichael Chan netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", 800c0c050c5SMichael Chan stringset); 801c0c050c5SMichael Chan break; 802c0c050c5SMichael Chan } 803c0c050c5SMichael Chan } 804c0c050c5SMichael Chan 805c0c050c5SMichael Chan static void bnxt_get_ringparam(struct net_device *dev, 80674624944SHao Chen struct ethtool_ringparam *ering, 80774624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 80874624944SHao Chen struct netlink_ext_ack *extack) 809c0c050c5SMichael Chan { 810c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 811c0c050c5SMichael Chan 812c1129b51SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) { 813c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA; 814c0c050c5SMichael Chan ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; 815b370517eSJakub Kicinski kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; 816c1129b51SMichael Chan } else { 817c1129b51SMichael Chan ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; 818c1129b51SMichael Chan ering->rx_jumbo_max_pending = 0; 819b370517eSJakub Kicinski kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED; 820c1129b51SMichael Chan } 821c0c050c5SMichael Chan ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; 822c0c050c5SMichael Chan 823c0c050c5SMichael Chan ering->rx_pending = bp->rx_ring_size; 824c0c050c5SMichael Chan ering->rx_jumbo_pending = bp->rx_agg_ring_size; 825c0c050c5SMichael Chan ering->tx_pending = bp->tx_ring_size; 826c0c050c5SMichael Chan } 827c0c050c5SMichael Chan 828c0c050c5SMichael Chan static int bnxt_set_ringparam(struct net_device *dev, 82974624944SHao Chen struct ethtool_ringparam *ering, 83074624944SHao Chen struct kernel_ethtool_ringparam *kernel_ering, 83174624944SHao Chen struct netlink_ext_ack *extack) 832c0c050c5SMichael Chan { 833c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 834c0c050c5SMichael Chan 835c0c050c5SMichael Chan if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || 836c0c050c5SMichael Chan (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || 8375bed8b07SMichael Chan (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) 838c0c050c5SMichael Chan return -EINVAL; 839c0c050c5SMichael Chan 840c0c050c5SMichael Chan if (netif_running(dev)) 841c0c050c5SMichael Chan bnxt_close_nic(bp, false, false); 842c0c050c5SMichael Chan 843c0c050c5SMichael Chan bp->rx_ring_size = ering->rx_pending; 844c0c050c5SMichael Chan bp->tx_ring_size = ering->tx_pending; 845c0c050c5SMichael Chan bnxt_set_ring_params(bp); 846c0c050c5SMichael Chan 847c0c050c5SMichael Chan if (netif_running(dev)) 848c0c050c5SMichael Chan return bnxt_open_nic(bp, false, false); 849c0c050c5SMichael Chan 850c0c050c5SMichael Chan return 0; 851c0c050c5SMichael Chan } 852c0c050c5SMichael Chan 853c0c050c5SMichael Chan static void bnxt_get_channels(struct net_device *dev, 854c0c050c5SMichael Chan struct ethtool_channels *channel) 855c0c050c5SMichael Chan { 856c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 857db4723b3SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 858c0c050c5SMichael Chan int max_rx_rings, max_tx_rings, tcs; 8594301304bSMichael Chan int max_tx_sch_inputs, tx_grps; 860db4723b3SMichael Chan 861db4723b3SMichael Chan /* Get the most up-to-date max_tx_sch_inputs. */ 862c1c2d774SPavan Chebbi if (netif_running(dev) && BNXT_NEW_RM(bp)) 863db4723b3SMichael Chan bnxt_hwrm_func_resc_qcaps(bp, false); 864db4723b3SMichael Chan max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; 865c0c050c5SMichael Chan 8666e6c5a57SMichael Chan bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); 867db4723b3SMichael Chan if (max_tx_sch_inputs) 868db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 8694301304bSMichael Chan 8704301304bSMichael Chan tcs = netdev_get_num_tc(dev); 8714301304bSMichael Chan tx_grps = max(tcs, 1); 8724301304bSMichael Chan if (bp->tx_nr_rings_xdp) 8734301304bSMichael Chan tx_grps++; 8744301304bSMichael Chan max_tx_rings /= tx_grps; 875a79a5276SMichael Chan channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); 876068c9ec6SMichael Chan 87718d6e4e2SSatish Baddipadige if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { 87818d6e4e2SSatish Baddipadige max_rx_rings = 0; 87918d6e4e2SSatish Baddipadige max_tx_rings = 0; 88018d6e4e2SSatish Baddipadige } 881db4723b3SMichael Chan if (max_tx_sch_inputs) 882db4723b3SMichael Chan max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); 88318d6e4e2SSatish Baddipadige 884c0c050c5SMichael Chan if (tcs > 1) 885c0c050c5SMichael Chan max_tx_rings /= tcs; 886c0c050c5SMichael Chan 887c0c050c5SMichael Chan channel->max_rx = max_rx_rings; 888c0c050c5SMichael Chan channel->max_tx = max_tx_rings; 889c0c050c5SMichael Chan channel->max_other = 0; 890068c9ec6SMichael Chan if (bp->flags & BNXT_FLAG_SHARED_RINGS) { 891068c9ec6SMichael Chan channel->combined_count = bp->rx_nr_rings; 89276595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp)) 89376595193SPrashant Sreedharan channel->combined_count--; 894068c9ec6SMichael Chan } else { 89576595193SPrashant Sreedharan if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { 896c0c050c5SMichael Chan channel->rx_count = bp->rx_nr_rings; 897c0c050c5SMichael Chan channel->tx_count = bp->tx_nr_rings_per_tc; 898c0c050c5SMichael Chan } 899068c9ec6SMichael Chan } 90076595193SPrashant Sreedharan } 901c0c050c5SMichael Chan 902c0c050c5SMichael Chan static int bnxt_set_channels(struct net_device *dev, 903c0c050c5SMichael Chan struct ethtool_channels *channel) 904c0c050c5SMichael Chan { 905c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 906d1e7925eSMichael Chan int req_tx_rings, req_rx_rings, tcs; 907068c9ec6SMichael Chan bool sh = false; 9085f449249SMichael Chan int tx_xdp = 0; 909d1e7925eSMichael Chan int rc = 0; 910c0c050c5SMichael Chan 911068c9ec6SMichael Chan if (channel->other_count) 912c0c050c5SMichael Chan return -EINVAL; 913c0c050c5SMichael Chan 914068c9ec6SMichael Chan if (!channel->combined_count && 915068c9ec6SMichael Chan (!channel->rx_count || !channel->tx_count)) 916068c9ec6SMichael Chan return -EINVAL; 917068c9ec6SMichael Chan 918068c9ec6SMichael Chan if (channel->combined_count && 919068c9ec6SMichael Chan (channel->rx_count || channel->tx_count)) 920068c9ec6SMichael Chan return -EINVAL; 921068c9ec6SMichael Chan 92276595193SPrashant Sreedharan if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || 92376595193SPrashant Sreedharan channel->tx_count)) 92476595193SPrashant Sreedharan return -EINVAL; 92576595193SPrashant Sreedharan 926068c9ec6SMichael Chan if (channel->combined_count) 927068c9ec6SMichael Chan sh = true; 928068c9ec6SMichael Chan 929c0c050c5SMichael Chan tcs = netdev_get_num_tc(dev); 930c0c050c5SMichael Chan 931391be5c2SMichael Chan req_tx_rings = sh ? channel->combined_count : channel->tx_count; 932d1e7925eSMichael Chan req_rx_rings = sh ? channel->combined_count : channel->rx_count; 9335f449249SMichael Chan if (bp->tx_nr_rings_xdp) { 9345f449249SMichael Chan if (!sh) { 9355f449249SMichael Chan netdev_err(dev, "Only combined mode supported when XDP is enabled.\n"); 9365f449249SMichael Chan return -EINVAL; 9375f449249SMichael Chan } 9385f449249SMichael Chan tx_xdp = req_rx_rings; 9395f449249SMichael Chan } 94098fdbe73SMichael Chan rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp); 941d1e7925eSMichael Chan if (rc) { 942d1e7925eSMichael Chan netdev_warn(dev, "Unable to allocate the requested rings\n"); 943d1e7925eSMichael Chan return rc; 944391be5c2SMichael Chan } 945391be5c2SMichael Chan 946bd3191b5SMichael Chan if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) != 947bd3191b5SMichael Chan bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) && 9484b70dce2SJuhee Kang netif_is_rxfh_configured(dev)) { 949bd3191b5SMichael Chan netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n"); 950bd3191b5SMichael Chan return -EINVAL; 951bd3191b5SMichael Chan } 952bd3191b5SMichael Chan 953c0c050c5SMichael Chan if (netif_running(dev)) { 954c0c050c5SMichael Chan if (BNXT_PF(bp)) { 955c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 956c0c050c5SMichael Chan * before PF unload 957c0c050c5SMichael Chan */ 958c0c050c5SMichael Chan } 959c0c050c5SMichael Chan rc = bnxt_close_nic(bp, true, false); 960c0c050c5SMichael Chan if (rc) { 961c0c050c5SMichael Chan netdev_err(bp->dev, "Set channel failure rc :%x\n", 962c0c050c5SMichael Chan rc); 963c0c050c5SMichael Chan return rc; 964c0c050c5SMichael Chan } 965c0c050c5SMichael Chan } 966c0c050c5SMichael Chan 967068c9ec6SMichael Chan if (sh) { 968068c9ec6SMichael Chan bp->flags |= BNXT_FLAG_SHARED_RINGS; 969d1e7925eSMichael Chan bp->rx_nr_rings = channel->combined_count; 970d1e7925eSMichael Chan bp->tx_nr_rings_per_tc = channel->combined_count; 971068c9ec6SMichael Chan } else { 972068c9ec6SMichael Chan bp->flags &= ~BNXT_FLAG_SHARED_RINGS; 973c0c050c5SMichael Chan bp->rx_nr_rings = channel->rx_count; 974c0c050c5SMichael Chan bp->tx_nr_rings_per_tc = channel->tx_count; 975068c9ec6SMichael Chan } 9765f449249SMichael Chan bp->tx_nr_rings_xdp = tx_xdp; 9775f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; 978c0c050c5SMichael Chan if (tcs > 1) 9795f449249SMichael Chan bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; 980068c9ec6SMichael Chan 981068c9ec6SMichael Chan bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) : 982068c9ec6SMichael Chan bp->tx_nr_rings + bp->rx_nr_rings; 983068c9ec6SMichael Chan 9842bcfa6f6SMichael Chan /* After changing number of rx channels, update NTUPLE feature. */ 9852bcfa6f6SMichael Chan netdev_update_features(dev); 986c0c050c5SMichael Chan if (netif_running(dev)) { 987c0c050c5SMichael Chan rc = bnxt_open_nic(bp, true, false); 988c0c050c5SMichael Chan if ((!rc) && BNXT_PF(bp)) { 989c0c050c5SMichael Chan /* TODO CHIMP_FW: Send message to all VF's 990c0c050c5SMichael Chan * to renable 991c0c050c5SMichael Chan */ 992c0c050c5SMichael Chan } 993d8c09f19SMichael Chan } else { 9941b3f0b75SMichael Chan rc = bnxt_reserve_rings(bp, true); 995c0c050c5SMichael Chan } 996c0c050c5SMichael Chan 997c0c050c5SMichael Chan return rc; 998c0c050c5SMichael Chan } 999c0c050c5SMichael Chan 1000c0c050c5SMichael Chan #ifdef CONFIG_RFS_ACCEL 1001c0c050c5SMichael Chan static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, 1002c0c050c5SMichael Chan u32 *rule_locs) 1003c0c050c5SMichael Chan { 1004c0c050c5SMichael Chan int i, j = 0; 1005c0c050c5SMichael Chan 1006c0c050c5SMichael Chan cmd->data = bp->ntp_fltr_count; 1007c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 1008c0c050c5SMichael Chan struct hlist_head *head; 1009c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 1010c0c050c5SMichael Chan 1011c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1012c0c050c5SMichael Chan rcu_read_lock(); 1013c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1014c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1015c0c050c5SMichael Chan break; 1016c0c050c5SMichael Chan rule_locs[j++] = fltr->sw_id; 1017c0c050c5SMichael Chan } 1018c0c050c5SMichael Chan rcu_read_unlock(); 1019c0c050c5SMichael Chan if (j == cmd->rule_cnt) 1020c0c050c5SMichael Chan break; 1021c0c050c5SMichael Chan } 1022c0c050c5SMichael Chan cmd->rule_cnt = j; 1023c0c050c5SMichael Chan return 0; 1024c0c050c5SMichael Chan } 1025c0c050c5SMichael Chan 1026c0c050c5SMichael Chan static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1027c0c050c5SMichael Chan { 1028c0c050c5SMichael Chan struct ethtool_rx_flow_spec *fs = 1029c0c050c5SMichael Chan (struct ethtool_rx_flow_spec *)&cmd->fs; 1030c0c050c5SMichael Chan struct bnxt_ntuple_filter *fltr; 1031c0c050c5SMichael Chan struct flow_keys *fkeys; 1032c0c050c5SMichael Chan int i, rc = -EINVAL; 1033c0c050c5SMichael Chan 1034b721cfafSstephen hemminger if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) 1035c0c050c5SMichael Chan return rc; 1036c0c050c5SMichael Chan 1037c0c050c5SMichael Chan for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { 1038c0c050c5SMichael Chan struct hlist_head *head; 1039c0c050c5SMichael Chan 1040c0c050c5SMichael Chan head = &bp->ntp_fltr_hash_tbl[i]; 1041c0c050c5SMichael Chan rcu_read_lock(); 1042c0c050c5SMichael Chan hlist_for_each_entry_rcu(fltr, head, hash) { 1043c0c050c5SMichael Chan if (fltr->sw_id == fs->location) 1044c0c050c5SMichael Chan goto fltr_found; 1045c0c050c5SMichael Chan } 1046c0c050c5SMichael Chan rcu_read_unlock(); 1047c0c050c5SMichael Chan } 1048c0c050c5SMichael Chan return rc; 1049c0c050c5SMichael Chan 1050c0c050c5SMichael Chan fltr_found: 1051c0c050c5SMichael Chan fkeys = &fltr->fkeys; 1052dda0e746SMichael Chan if (fkeys->basic.n_proto == htons(ETH_P_IP)) { 1053c0c050c5SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1054c0c050c5SMichael Chan fs->flow_type = TCP_V4_FLOW; 1055c0c050c5SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1056c0c050c5SMichael Chan fs->flow_type = UDP_V4_FLOW; 1057c0c050c5SMichael Chan else 1058c0c050c5SMichael Chan goto fltr_err; 1059c0c050c5SMichael Chan 1060c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; 1061c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); 1062c0c050c5SMichael Chan 1063c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; 1064c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); 1065c0c050c5SMichael Chan 1066c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; 1067c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); 1068c0c050c5SMichael Chan 1069c0c050c5SMichael Chan fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; 1070c0c050c5SMichael Chan fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); 1071dda0e746SMichael Chan } else { 1072dda0e746SMichael Chan int i; 1073dda0e746SMichael Chan 1074dda0e746SMichael Chan if (fkeys->basic.ip_proto == IPPROTO_TCP) 1075dda0e746SMichael Chan fs->flow_type = TCP_V6_FLOW; 1076dda0e746SMichael Chan else if (fkeys->basic.ip_proto == IPPROTO_UDP) 1077dda0e746SMichael Chan fs->flow_type = UDP_V6_FLOW; 1078dda0e746SMichael Chan else 1079dda0e746SMichael Chan goto fltr_err; 1080dda0e746SMichael Chan 1081dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = 1082dda0e746SMichael Chan fkeys->addrs.v6addrs.src; 1083dda0e746SMichael Chan *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = 1084dda0e746SMichael Chan fkeys->addrs.v6addrs.dst; 1085dda0e746SMichael Chan for (i = 0; i < 4; i++) { 1086dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); 1087dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); 1088dda0e746SMichael Chan } 1089dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; 1090dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); 1091dda0e746SMichael Chan 1092dda0e746SMichael Chan fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; 1093dda0e746SMichael Chan fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); 1094dda0e746SMichael Chan } 1095c0c050c5SMichael Chan 1096c0c050c5SMichael Chan fs->ring_cookie = fltr->rxq; 1097c0c050c5SMichael Chan rc = 0; 1098c0c050c5SMichael Chan 1099c0c050c5SMichael Chan fltr_err: 1100c0c050c5SMichael Chan rcu_read_unlock(); 1101c0c050c5SMichael Chan 1102c0c050c5SMichael Chan return rc; 1103c0c050c5SMichael Chan } 1104a011952aSMichael Chan #endif 1105a011952aSMichael Chan 1106a011952aSMichael Chan static u64 get_ethtool_ipv4_rss(struct bnxt *bp) 1107a011952aSMichael Chan { 1108a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) 1109a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1110a011952aSMichael Chan return 0; 1111a011952aSMichael Chan } 1112a011952aSMichael Chan 1113a011952aSMichael Chan static u64 get_ethtool_ipv6_rss(struct bnxt *bp) 1114a011952aSMichael Chan { 1115a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) 1116a011952aSMichael Chan return RXH_IP_SRC | RXH_IP_DST; 1117a011952aSMichael Chan return 0; 1118a011952aSMichael Chan } 1119a011952aSMichael Chan 1120a011952aSMichael Chan static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1121a011952aSMichael Chan { 1122a011952aSMichael Chan cmd->data = 0; 1123a011952aSMichael Chan switch (cmd->flow_type) { 1124a011952aSMichael Chan case TCP_V4_FLOW: 1125a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) 1126a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1127a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1128a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1129a011952aSMichael Chan break; 1130a011952aSMichael Chan case UDP_V4_FLOW: 1131a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) 1132a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1133a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1134df561f66SGustavo A. R. Silva fallthrough; 1135a011952aSMichael Chan case SCTP_V4_FLOW: 1136a011952aSMichael Chan case AH_ESP_V4_FLOW: 1137a011952aSMichael Chan case AH_V4_FLOW: 1138a011952aSMichael Chan case ESP_V4_FLOW: 1139a011952aSMichael Chan case IPV4_FLOW: 1140a011952aSMichael Chan cmd->data |= get_ethtool_ipv4_rss(bp); 1141a011952aSMichael Chan break; 1142a011952aSMichael Chan 1143a011952aSMichael Chan case TCP_V6_FLOW: 1144a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) 1145a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1146a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1147a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1148a011952aSMichael Chan break; 1149a011952aSMichael Chan case UDP_V6_FLOW: 1150a011952aSMichael Chan if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) 1151a011952aSMichael Chan cmd->data |= RXH_IP_SRC | RXH_IP_DST | 1152a011952aSMichael Chan RXH_L4_B_0_1 | RXH_L4_B_2_3; 1153df561f66SGustavo A. R. Silva fallthrough; 1154a011952aSMichael Chan case SCTP_V6_FLOW: 1155a011952aSMichael Chan case AH_ESP_V6_FLOW: 1156a011952aSMichael Chan case AH_V6_FLOW: 1157a011952aSMichael Chan case ESP_V6_FLOW: 1158a011952aSMichael Chan case IPV6_FLOW: 1159a011952aSMichael Chan cmd->data |= get_ethtool_ipv6_rss(bp); 1160a011952aSMichael Chan break; 1161a011952aSMichael Chan } 1162a011952aSMichael Chan return 0; 1163a011952aSMichael Chan } 1164a011952aSMichael Chan 1165a011952aSMichael Chan #define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 1166a011952aSMichael Chan #define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) 1167a011952aSMichael Chan 1168a011952aSMichael Chan static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) 1169a011952aSMichael Chan { 1170a011952aSMichael Chan u32 rss_hash_cfg = bp->rss_hash_cfg; 1171a011952aSMichael Chan int tuple, rc = 0; 1172a011952aSMichael Chan 1173a011952aSMichael Chan if (cmd->data == RXH_4TUPLE) 1174a011952aSMichael Chan tuple = 4; 1175a011952aSMichael Chan else if (cmd->data == RXH_2TUPLE) 1176a011952aSMichael Chan tuple = 2; 1177a011952aSMichael Chan else if (!cmd->data) 1178a011952aSMichael Chan tuple = 0; 1179a011952aSMichael Chan else 1180a011952aSMichael Chan return -EINVAL; 1181a011952aSMichael Chan 1182a011952aSMichael Chan if (cmd->flow_type == TCP_V4_FLOW) { 1183a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1184a011952aSMichael Chan if (tuple == 4) 1185a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; 1186a011952aSMichael Chan } else if (cmd->flow_type == UDP_V4_FLOW) { 1187a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1188a011952aSMichael Chan return -EINVAL; 1189a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1190a011952aSMichael Chan if (tuple == 4) 1191a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; 1192a011952aSMichael Chan } else if (cmd->flow_type == TCP_V6_FLOW) { 1193a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1194a011952aSMichael Chan if (tuple == 4) 1195a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; 1196a011952aSMichael Chan } else if (cmd->flow_type == UDP_V6_FLOW) { 1197a011952aSMichael Chan if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP)) 1198a011952aSMichael Chan return -EINVAL; 1199a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1200a011952aSMichael Chan if (tuple == 4) 1201a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; 1202a011952aSMichael Chan } else if (tuple == 4) { 1203a011952aSMichael Chan return -EINVAL; 1204a011952aSMichael Chan } 1205a011952aSMichael Chan 1206a011952aSMichael Chan switch (cmd->flow_type) { 1207a011952aSMichael Chan case TCP_V4_FLOW: 1208a011952aSMichael Chan case UDP_V4_FLOW: 1209a011952aSMichael Chan case SCTP_V4_FLOW: 1210a011952aSMichael Chan case AH_ESP_V4_FLOW: 1211a011952aSMichael Chan case AH_V4_FLOW: 1212a011952aSMichael Chan case ESP_V4_FLOW: 1213a011952aSMichael Chan case IPV4_FLOW: 1214a011952aSMichael Chan if (tuple == 2) 1215a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1216a011952aSMichael Chan else if (!tuple) 1217a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; 1218a011952aSMichael Chan break; 1219a011952aSMichael Chan 1220a011952aSMichael Chan case TCP_V6_FLOW: 1221a011952aSMichael Chan case UDP_V6_FLOW: 1222a011952aSMichael Chan case SCTP_V6_FLOW: 1223a011952aSMichael Chan case AH_ESP_V6_FLOW: 1224a011952aSMichael Chan case AH_V6_FLOW: 1225a011952aSMichael Chan case ESP_V6_FLOW: 1226a011952aSMichael Chan case IPV6_FLOW: 1227a011952aSMichael Chan if (tuple == 2) 1228a011952aSMichael Chan rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1229a011952aSMichael Chan else if (!tuple) 1230a011952aSMichael Chan rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; 1231a011952aSMichael Chan break; 1232a011952aSMichael Chan } 1233a011952aSMichael Chan 1234a011952aSMichael Chan if (bp->rss_hash_cfg == rss_hash_cfg) 1235a011952aSMichael Chan return 0; 1236a011952aSMichael Chan 123798a4322bSEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA) 123898a4322bSEdwin Peer bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg; 1239a011952aSMichael Chan bp->rss_hash_cfg = rss_hash_cfg; 1240a011952aSMichael Chan if (netif_running(bp->dev)) { 1241a011952aSMichael Chan bnxt_close_nic(bp, false, false); 1242a011952aSMichael Chan rc = bnxt_open_nic(bp, false, false); 1243a011952aSMichael Chan } 1244a011952aSMichael Chan return rc; 1245a011952aSMichael Chan } 1246c0c050c5SMichael Chan 1247c0c050c5SMichael Chan static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 1248c0c050c5SMichael Chan u32 *rule_locs) 1249c0c050c5SMichael Chan { 1250c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1251c0c050c5SMichael Chan int rc = 0; 1252c0c050c5SMichael Chan 1253c0c050c5SMichael Chan switch (cmd->cmd) { 1254a011952aSMichael Chan #ifdef CONFIG_RFS_ACCEL 1255c0c050c5SMichael Chan case ETHTOOL_GRXRINGS: 1256c0c050c5SMichael Chan cmd->data = bp->rx_nr_rings; 1257c0c050c5SMichael Chan break; 1258c0c050c5SMichael Chan 1259c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLCNT: 1260c0c050c5SMichael Chan cmd->rule_cnt = bp->ntp_fltr_count; 1261c0c050c5SMichael Chan cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 1262c0c050c5SMichael Chan break; 1263c0c050c5SMichael Chan 1264c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLALL: 1265c0c050c5SMichael Chan rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 1266c0c050c5SMichael Chan break; 1267c0c050c5SMichael Chan 1268c0c050c5SMichael Chan case ETHTOOL_GRXCLSRULE: 1269c0c050c5SMichael Chan rc = bnxt_grxclsrule(bp, cmd); 1270c0c050c5SMichael Chan break; 1271a011952aSMichael Chan #endif 1272a011952aSMichael Chan 1273a011952aSMichael Chan case ETHTOOL_GRXFH: 1274a011952aSMichael Chan rc = bnxt_grxfh(bp, cmd); 1275a011952aSMichael Chan break; 1276c0c050c5SMichael Chan 1277c0c050c5SMichael Chan default: 1278c0c050c5SMichael Chan rc = -EOPNOTSUPP; 1279c0c050c5SMichael Chan break; 1280c0c050c5SMichael Chan } 1281c0c050c5SMichael Chan 1282c0c050c5SMichael Chan return rc; 1283c0c050c5SMichael Chan } 1284a011952aSMichael Chan 1285a011952aSMichael Chan static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 1286a011952aSMichael Chan { 1287a011952aSMichael Chan struct bnxt *bp = netdev_priv(dev); 1288a011952aSMichael Chan int rc; 1289a011952aSMichael Chan 1290a011952aSMichael Chan switch (cmd->cmd) { 1291a011952aSMichael Chan case ETHTOOL_SRXFH: 1292a011952aSMichael Chan rc = bnxt_srxfh(bp, cmd); 1293a011952aSMichael Chan break; 1294a011952aSMichael Chan 1295a011952aSMichael Chan default: 1296a011952aSMichael Chan rc = -EOPNOTSUPP; 1297a011952aSMichael Chan break; 1298a011952aSMichael Chan } 1299a011952aSMichael Chan return rc; 1300a011952aSMichael Chan } 1301c0c050c5SMichael Chan 1302b73c1d08SMichael Chan u32 bnxt_get_rxfh_indir_size(struct net_device *dev) 1303c0c050c5SMichael Chan { 1304b73c1d08SMichael Chan struct bnxt *bp = netdev_priv(dev); 1305b73c1d08SMichael Chan 1306b73c1d08SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 1307b73c1d08SMichael Chan return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 1308c0c050c5SMichael Chan return HW_HASH_INDEX_SIZE; 1309c0c050c5SMichael Chan } 1310c0c050c5SMichael Chan 1311c0c050c5SMichael Chan static u32 bnxt_get_rxfh_key_size(struct net_device *dev) 1312c0c050c5SMichael Chan { 1313c0c050c5SMichael Chan return HW_HASH_KEY_SIZE; 1314c0c050c5SMichael Chan } 1315c0c050c5SMichael Chan 1316c0c050c5SMichael Chan static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 1317c0c050c5SMichael Chan u8 *hfunc) 1318c0c050c5SMichael Chan { 1319c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 13207991cb9cSMichael Chan struct bnxt_vnic_info *vnic; 1321adc38ac6SMichael Chan u32 i, tbl_size; 1322c0c050c5SMichael Chan 1323c0c050c5SMichael Chan if (hfunc) 1324c0c050c5SMichael Chan *hfunc = ETH_RSS_HASH_TOP; 1325c0c050c5SMichael Chan 13267991cb9cSMichael Chan if (!bp->vnic_info) 13277991cb9cSMichael Chan return 0; 13287991cb9cSMichael Chan 13297991cb9cSMichael Chan vnic = &bp->vnic_info[0]; 1330adc38ac6SMichael Chan if (indir && bp->rss_indir_tbl) { 1331adc38ac6SMichael Chan tbl_size = bnxt_get_rxfh_indir_size(dev); 1332adc38ac6SMichael Chan for (i = 0; i < tbl_size; i++) 1333adc38ac6SMichael Chan indir[i] = bp->rss_indir_tbl[i]; 13347991cb9cSMichael Chan } 1335c0c050c5SMichael Chan 13367991cb9cSMichael Chan if (key && vnic->rss_hash_key) 1337c0c050c5SMichael Chan memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 1338c0c050c5SMichael Chan 1339c0c050c5SMichael Chan return 0; 1340c0c050c5SMichael Chan } 1341c0c050c5SMichael Chan 1342bd3191b5SMichael Chan static int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 1343bd3191b5SMichael Chan const u8 *key, const u8 hfunc) 1344bd3191b5SMichael Chan { 1345bd3191b5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1346bd3191b5SMichael Chan int rc = 0; 1347bd3191b5SMichael Chan 1348bd3191b5SMichael Chan if (hfunc && hfunc != ETH_RSS_HASH_TOP) 1349bd3191b5SMichael Chan return -EOPNOTSUPP; 1350bd3191b5SMichael Chan 1351bd3191b5SMichael Chan if (key) 1352bd3191b5SMichael Chan return -EOPNOTSUPP; 1353bd3191b5SMichael Chan 1354bd3191b5SMichael Chan if (indir) { 1355bd3191b5SMichael Chan u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 1356bd3191b5SMichael Chan 1357bd3191b5SMichael Chan for (i = 0; i < tbl_size; i++) 1358bd3191b5SMichael Chan bp->rss_indir_tbl[i] = indir[i]; 1359bd3191b5SMichael Chan pad = bp->rss_indir_tbl_entries - tbl_size; 1360bd3191b5SMichael Chan if (pad) 1361bd3191b5SMichael Chan memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 1362bd3191b5SMichael Chan } 1363bd3191b5SMichael Chan 1364bd3191b5SMichael Chan if (netif_running(bp->dev)) { 1365bd3191b5SMichael Chan bnxt_close_nic(bp, false, false); 1366bd3191b5SMichael Chan rc = bnxt_open_nic(bp, false, false); 1367bd3191b5SMichael Chan } 1368bd3191b5SMichael Chan return rc; 1369bd3191b5SMichael Chan } 1370bd3191b5SMichael Chan 1371c0c050c5SMichael Chan static void bnxt_get_drvinfo(struct net_device *dev, 1372c0c050c5SMichael Chan struct ethtool_drvinfo *info) 1373c0c050c5SMichael Chan { 1374c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1375c0c050c5SMichael Chan 1376f029c781SWolfram Sang strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 1377f029c781SWolfram Sang strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 1378f029c781SWolfram Sang strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 13795c8227d0SMichael Chan info->n_stats = bnxt_get_num_stats(bp); 1380eb513658SMichael Chan info->testinfo_len = bp->num_tests; 1381c0c050c5SMichael Chan /* TODO CHIMP_FW: eeprom dump details */ 1382c0c050c5SMichael Chan info->eedump_len = 0; 1383c0c050c5SMichael Chan /* TODO CHIMP FW: reg dump details */ 1384c0c050c5SMichael Chan info->regdump_len = 0; 1385c0c050c5SMichael Chan } 1386c0c050c5SMichael Chan 1387b5d600b0SVasundhara Volam static int bnxt_get_regs_len(struct net_device *dev) 1388b5d600b0SVasundhara Volam { 1389b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1390b5d600b0SVasundhara Volam int reg_len; 1391b5d600b0SVasundhara Volam 1392f0f47b2fSVasundhara Volam if (!BNXT_PF(bp)) 1393f0f47b2fSVasundhara Volam return -EOPNOTSUPP; 1394f0f47b2fSVasundhara Volam 1395b5d600b0SVasundhara Volam reg_len = BNXT_PXP_REG_LEN; 1396b5d600b0SVasundhara Volam 1397b5d600b0SVasundhara Volam if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 1398b5d600b0SVasundhara Volam reg_len += sizeof(struct pcie_ctx_hw_stats); 1399b5d600b0SVasundhara Volam 1400b5d600b0SVasundhara Volam return reg_len; 1401b5d600b0SVasundhara Volam } 1402b5d600b0SVasundhara Volam 1403b5d600b0SVasundhara Volam static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 1404b5d600b0SVasundhara Volam void *_p) 1405b5d600b0SVasundhara Volam { 1406b5d600b0SVasundhara Volam struct pcie_ctx_hw_stats *hw_pcie_stats; 1407bbf33d1dSEdwin Peer struct hwrm_pcie_qstats_input *req; 1408b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1409b5d600b0SVasundhara Volam dma_addr_t hw_pcie_stats_addr; 1410b5d600b0SVasundhara Volam int rc; 1411b5d600b0SVasundhara Volam 1412b5d600b0SVasundhara Volam regs->version = 0; 1413b5d600b0SVasundhara Volam bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 1414b5d600b0SVasundhara Volam 1415b5d600b0SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 1416b5d600b0SVasundhara Volam return; 1417b5d600b0SVasundhara Volam 1418bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) 1419b5d600b0SVasundhara Volam return; 1420b5d600b0SVasundhara Volam 1421bbf33d1dSEdwin Peer hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), 1422bbf33d1dSEdwin Peer &hw_pcie_stats_addr); 1423bbf33d1dSEdwin Peer if (!hw_pcie_stats) { 1424bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1425bbf33d1dSEdwin Peer return; 1426bbf33d1dSEdwin Peer } 1427bbf33d1dSEdwin Peer 1428b5d600b0SVasundhara Volam regs->version = 1; 1429bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold on to slice */ 1430bbf33d1dSEdwin Peer req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 1431bbf33d1dSEdwin Peer req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 1432bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 1433b5d600b0SVasundhara Volam if (!rc) { 1434b5d600b0SVasundhara Volam __le64 *src = (__le64 *)hw_pcie_stats; 1435b5d600b0SVasundhara Volam u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 1436b5d600b0SVasundhara Volam int i; 1437b5d600b0SVasundhara Volam 1438b5d600b0SVasundhara Volam for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 1439b5d600b0SVasundhara Volam dst[i] = le64_to_cpu(src[i]); 1440b5d600b0SVasundhara Volam } 1441bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1442b5d600b0SVasundhara Volam } 1443b5d600b0SVasundhara Volam 14448e202366SMichael Chan static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14458e202366SMichael Chan { 14468e202366SMichael Chan struct bnxt *bp = netdev_priv(dev); 14478e202366SMichael Chan 14488e202366SMichael Chan wol->supported = 0; 14498e202366SMichael Chan wol->wolopts = 0; 14508e202366SMichael Chan memset(&wol->sopass, 0, sizeof(wol->sopass)); 14518e202366SMichael Chan if (bp->flags & BNXT_FLAG_WOL_CAP) { 14528e202366SMichael Chan wol->supported = WAKE_MAGIC; 14538e202366SMichael Chan if (bp->wol) 14548e202366SMichael Chan wol->wolopts = WAKE_MAGIC; 14558e202366SMichael Chan } 14568e202366SMichael Chan } 14578e202366SMichael Chan 14585282db6cSMichael Chan static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14595282db6cSMichael Chan { 14605282db6cSMichael Chan struct bnxt *bp = netdev_priv(dev); 14615282db6cSMichael Chan 14625282db6cSMichael Chan if (wol->wolopts & ~WAKE_MAGIC) 14635282db6cSMichael Chan return -EINVAL; 14645282db6cSMichael Chan 14655282db6cSMichael Chan if (wol->wolopts & WAKE_MAGIC) { 14665282db6cSMichael Chan if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 14675282db6cSMichael Chan return -EINVAL; 14685282db6cSMichael Chan if (!bp->wol) { 14695282db6cSMichael Chan if (bnxt_hwrm_alloc_wol_fltr(bp)) 14705282db6cSMichael Chan return -EBUSY; 14715282db6cSMichael Chan bp->wol = 1; 14725282db6cSMichael Chan } 14735282db6cSMichael Chan } else { 14745282db6cSMichael Chan if (bp->wol) { 14755282db6cSMichael Chan if (bnxt_hwrm_free_wol_fltr(bp)) 14765282db6cSMichael Chan return -EBUSY; 14775282db6cSMichael Chan bp->wol = 0; 14785282db6cSMichael Chan } 14795282db6cSMichael Chan } 14805282db6cSMichael Chan return 0; 14815282db6cSMichael Chan } 14825282db6cSMichael Chan 1483170ce013SMichael Chan u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 1484c0c050c5SMichael Chan { 1485c0c050c5SMichael Chan u32 speed_mask = 0; 1486c0c050c5SMichael Chan 1487c0c050c5SMichael Chan /* TODO: support 25GB, 40GB, 50GB with different cable type */ 1488c0c050c5SMichael Chan /* set the advertised speeds */ 1489c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 1490c0c050c5SMichael Chan speed_mask |= ADVERTISED_100baseT_Full; 1491c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 1492c0c050c5SMichael Chan speed_mask |= ADVERTISED_1000baseT_Full; 1493c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 1494c0c050c5SMichael Chan speed_mask |= ADVERTISED_2500baseX_Full; 1495c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 1496c0c050c5SMichael Chan speed_mask |= ADVERTISED_10000baseT_Full; 1497c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 14981c49c421SMichael Chan speed_mask |= ADVERTISED_40000baseCR4_Full; 149927c4d578SMichael Chan 150027c4d578SMichael Chan if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 150127c4d578SMichael Chan speed_mask |= ADVERTISED_Pause; 150227c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_TX) 150327c4d578SMichael Chan speed_mask |= ADVERTISED_Asym_Pause; 150427c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_RX) 150527c4d578SMichael Chan speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 150627c4d578SMichael Chan 1507c0c050c5SMichael Chan return speed_mask; 1508c0c050c5SMichael Chan } 1509c0c050c5SMichael Chan 151000c04a92SMichael Chan #define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 151100c04a92SMichael Chan { \ 151200c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 151300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151400c04a92SMichael Chan 100baseT_Full); \ 151500c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 151600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151700c04a92SMichael Chan 1000baseT_Full); \ 151800c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 151900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152000c04a92SMichael Chan 10000baseT_Full); \ 152100c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 152200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152300c04a92SMichael Chan 25000baseCR_Full); \ 152400c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 152500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152600c04a92SMichael Chan 40000baseCR4_Full);\ 152700c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 152800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152900c04a92SMichael Chan 50000baseCR2_Full);\ 153038a21b34SDeepak Khungar if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 153138a21b34SDeepak Khungar ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153238a21b34SDeepak Khungar 100000baseCR4_Full);\ 153300c04a92SMichael Chan if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 153400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153500c04a92SMichael Chan Pause); \ 153600c04a92SMichael Chan if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 153700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode( \ 153800c04a92SMichael Chan lk_ksettings, name, Asym_Pause);\ 153900c04a92SMichael Chan } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 154000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 154100c04a92SMichael Chan Asym_Pause); \ 154200c04a92SMichael Chan } \ 154300c04a92SMichael Chan } 154400c04a92SMichael Chan 154500c04a92SMichael Chan #define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 154600c04a92SMichael Chan { \ 154700c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154800c04a92SMichael Chan 100baseT_Full) || \ 154900c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155000c04a92SMichael Chan 100baseT_Half)) \ 155100c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 155200c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155300c04a92SMichael Chan 1000baseT_Full) || \ 155400c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155500c04a92SMichael Chan 1000baseT_Half)) \ 155600c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 155700c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155800c04a92SMichael Chan 10000baseT_Full)) \ 155900c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 156000c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156100c04a92SMichael Chan 25000baseCR_Full)) \ 156200c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 156300c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156400c04a92SMichael Chan 40000baseCR4_Full)) \ 156500c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 156600c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156700c04a92SMichael Chan 50000baseCR2_Full)) \ 156800c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 156938a21b34SDeepak Khungar if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 157038a21b34SDeepak Khungar 100000baseCR4_Full)) \ 157138a21b34SDeepak Khungar (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 157200c04a92SMichael Chan } 157300c04a92SMichael Chan 1574532262baSEdwin Peer #define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1575532262baSEdwin Peer { \ 1576532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 1577532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1578532262baSEdwin Peer 50000baseCR_Full); \ 1579532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 1580532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1581532262baSEdwin Peer 100000baseCR2_Full);\ 1582532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 1583532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1584532262baSEdwin Peer 200000baseCR4_Full);\ 1585532262baSEdwin Peer } 1586532262baSEdwin Peer 1587532262baSEdwin Peer #define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1588532262baSEdwin Peer { \ 1589532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1590532262baSEdwin Peer 50000baseCR_Full)) \ 1591532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 1592532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1593532262baSEdwin Peer 100000baseCR2_Full)) \ 1594532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 1595532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1596532262baSEdwin Peer 200000baseCR4_Full)) \ 1597532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 1598532262baSEdwin Peer } 1599532262baSEdwin Peer 16008b277589SMichael Chan static void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 16018b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16028b277589SMichael Chan { 16038b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16048b277589SMichael Chan 16058b277589SMichael Chan if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 16068b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16078b277589SMichael Chan lk_ksettings->link_modes.advertising); 16088b277589SMichael Chan return; 16098b277589SMichael Chan } 16108b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 16118b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16128b277589SMichael Chan lk_ksettings->link_modes.advertising); 16138b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 16148b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16158b277589SMichael Chan lk_ksettings->link_modes.advertising); 16168b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 16178b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16188b277589SMichael Chan lk_ksettings->link_modes.advertising); 16198b277589SMichael Chan } 16208b277589SMichael Chan 162100c04a92SMichael Chan static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 162200c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 162327c4d578SMichael Chan { 162468515a18SMichael Chan u16 fw_speeds = link_info->advertising; 162527c4d578SMichael Chan u8 fw_pause = 0; 162627c4d578SMichael Chan 162727c4d578SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 162827c4d578SMichael Chan fw_pause = link_info->auto_pause_setting; 162927c4d578SMichael Chan 163000c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 1631532262baSEdwin Peer fw_speeds = link_info->advertising_pam4; 1632532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 16338b277589SMichael Chan bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 163427c4d578SMichael Chan } 163527c4d578SMichael Chan 163600c04a92SMichael Chan static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 163700c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16383277360eSMichael Chan { 16393277360eSMichael Chan u16 fw_speeds = link_info->lp_auto_link_speeds; 16403277360eSMichael Chan u8 fw_pause = 0; 16413277360eSMichael Chan 16423277360eSMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 16433277360eSMichael Chan fw_pause = link_info->lp_pause; 16443277360eSMichael Chan 164500c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 164600c04a92SMichael Chan lp_advertising); 1647532262baSEdwin Peer fw_speeds = link_info->lp_auto_pam4_link_speeds; 1648532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 16493277360eSMichael Chan } 16503277360eSMichael Chan 16518b277589SMichael Chan static void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 16528b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16538b277589SMichael Chan { 16548b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16558b277589SMichael Chan 16568b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 16578b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16588b277589SMichael Chan lk_ksettings->link_modes.supported); 16598b277589SMichael Chan return; 16608b277589SMichael Chan } 16618b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 16628b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16638b277589SMichael Chan lk_ksettings->link_modes.supported); 16648b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 16658b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16668b277589SMichael Chan lk_ksettings->link_modes.supported); 16678b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 16688b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16698b277589SMichael Chan lk_ksettings->link_modes.supported); 16708b277589SMichael Chan } 16718b277589SMichael Chan 167200c04a92SMichael Chan static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 167300c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16744b32caccSMichael Chan { 16759a3bc77eSMichael Chan struct bnxt *bp = container_of(link_info, struct bnxt, link_info); 16764b32caccSMichael Chan u16 fw_speeds = link_info->support_speeds; 16774b32caccSMichael Chan 167800c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 1679532262baSEdwin Peer fw_speeds = link_info->support_pam4_speeds; 1680532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16814b32caccSMichael Chan 16829a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) { 16839a3bc77eSMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 16849a3bc77eSMichael Chan Pause); 168500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 168600c04a92SMichael Chan Asym_Pause); 16879a3bc77eSMichael Chan } 168893ed8117SMichael Chan 1689532262baSEdwin Peer if (link_info->support_auto_speeds || 1690532262baSEdwin Peer link_info->support_pam4_auto_speeds) 169100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 169200c04a92SMichael Chan Autoneg); 16938b277589SMichael Chan bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 169493ed8117SMichael Chan } 169593ed8117SMichael Chan 1696c0c050c5SMichael Chan u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 1697c0c050c5SMichael Chan { 1698c0c050c5SMichael Chan switch (fw_link_speed) { 1699c0c050c5SMichael Chan case BNXT_LINK_SPEED_100MB: 1700c0c050c5SMichael Chan return SPEED_100; 1701c0c050c5SMichael Chan case BNXT_LINK_SPEED_1GB: 1702c0c050c5SMichael Chan return SPEED_1000; 1703c0c050c5SMichael Chan case BNXT_LINK_SPEED_2_5GB: 1704c0c050c5SMichael Chan return SPEED_2500; 1705c0c050c5SMichael Chan case BNXT_LINK_SPEED_10GB: 1706c0c050c5SMichael Chan return SPEED_10000; 1707c0c050c5SMichael Chan case BNXT_LINK_SPEED_20GB: 1708c0c050c5SMichael Chan return SPEED_20000; 1709c0c050c5SMichael Chan case BNXT_LINK_SPEED_25GB: 1710c0c050c5SMichael Chan return SPEED_25000; 1711c0c050c5SMichael Chan case BNXT_LINK_SPEED_40GB: 1712c0c050c5SMichael Chan return SPEED_40000; 1713c0c050c5SMichael Chan case BNXT_LINK_SPEED_50GB: 1714c0c050c5SMichael Chan return SPEED_50000; 171538a21b34SDeepak Khungar case BNXT_LINK_SPEED_100GB: 171638a21b34SDeepak Khungar return SPEED_100000; 1717*581bce7bSMichael Chan case BNXT_LINK_SPEED_200GB: 1718*581bce7bSMichael Chan return SPEED_200000; 1719c0c050c5SMichael Chan default: 1720c0c050c5SMichael Chan return SPEED_UNKNOWN; 1721c0c050c5SMichael Chan } 1722c0c050c5SMichael Chan } 1723c0c050c5SMichael Chan 172400c04a92SMichael Chan static int bnxt_get_link_ksettings(struct net_device *dev, 172500c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 1726c0c050c5SMichael Chan { 1727c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1728c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 172900c04a92SMichael Chan struct ethtool_link_settings *base = &lk_ksettings->base; 173000c04a92SMichael Chan u32 ethtool_speed; 1731c0c050c5SMichael Chan 173200c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 1733e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 173400c04a92SMichael Chan bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 1735c0c050c5SMichael Chan 173600c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 1737b763499eSMichael Chan if (link_info->autoneg) { 173800c04a92SMichael Chan bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 173900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, 174000c04a92SMichael Chan advertising, Autoneg); 174100c04a92SMichael Chan base->autoneg = AUTONEG_ENABLE; 174200c04a92SMichael Chan base->duplex = DUPLEX_UNKNOWN; 174383d8f5e9SMichael Chan if (link_info->phy_link_status == BNXT_LINK_LINK) { 174483d8f5e9SMichael Chan bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 174583d8f5e9SMichael Chan if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 174600c04a92SMichael Chan base->duplex = DUPLEX_FULL; 174729c262feSMichael Chan else 174800c04a92SMichael Chan base->duplex = DUPLEX_HALF; 174983d8f5e9SMichael Chan } 175083d8f5e9SMichael Chan ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 1751c0c050c5SMichael Chan } else { 175200c04a92SMichael Chan base->autoneg = AUTONEG_DISABLE; 175329c262feSMichael Chan ethtool_speed = 175429c262feSMichael Chan bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 175500c04a92SMichael Chan base->duplex = DUPLEX_HALF; 175629c262feSMichael Chan if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 175700c04a92SMichael Chan base->duplex = DUPLEX_FULL; 1758c0c050c5SMichael Chan } 175900c04a92SMichael Chan base->speed = ethtool_speed; 1760c0c050c5SMichael Chan 176100c04a92SMichael Chan base->port = PORT_NONE; 1762c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 176300c04a92SMichael Chan base->port = PORT_TP; 176400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 176500c04a92SMichael Chan TP); 176600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176700c04a92SMichael Chan TP); 1768c0c050c5SMichael Chan } else { 176900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 177000c04a92SMichael Chan FIBRE); 177100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 177200c04a92SMichael Chan FIBRE); 1773c0c050c5SMichael Chan 1774c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 177500c04a92SMichael Chan base->port = PORT_DA; 1776c0c050c5SMichael Chan else if (link_info->media_type == 1777c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 177800c04a92SMichael Chan base->port = PORT_FIBRE; 1779c0c050c5SMichael Chan } 178000c04a92SMichael Chan base->phy_address = link_info->phy_addr; 1781e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1782c0c050c5SMichael Chan 1783c0c050c5SMichael Chan return 0; 1784c0c050c5SMichael Chan } 1785c0c050c5SMichael Chan 1786f00530bfSEdwin Peer static int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 1787c0c050c5SMichael Chan { 17889d9cee08SMichael Chan struct bnxt *bp = netdev_priv(dev); 17899d9cee08SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 1790532262baSEdwin Peer u16 support_pam4_spds = link_info->support_pam4_speeds; 17919d9cee08SMichael Chan u16 support_spds = link_info->support_speeds; 1792532262baSEdwin Peer u8 sig_mode = BNXT_SIG_MODE_NRZ; 1793f00530bfSEdwin Peer u16 fw_speed = 0; 17949d9cee08SMichael Chan 1795c0c050c5SMichael Chan switch (ethtool_speed) { 1796c0c050c5SMichael Chan case SPEED_100: 17979d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 1798f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17999d9cee08SMichael Chan break; 1800c0c050c5SMichael Chan case SPEED_1000: 18019d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 1802f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 18039d9cee08SMichael Chan break; 1804c0c050c5SMichael Chan case SPEED_2500: 18059d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 1806f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 18079d9cee08SMichael Chan break; 1808c0c050c5SMichael Chan case SPEED_10000: 18099d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 1810f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 18119d9cee08SMichael Chan break; 1812c0c050c5SMichael Chan case SPEED_20000: 18139d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 1814f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 18159d9cee08SMichael Chan break; 1816c0c050c5SMichael Chan case SPEED_25000: 18179d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 1818f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 18199d9cee08SMichael Chan break; 1820c0c050c5SMichael Chan case SPEED_40000: 18219d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 1822f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 18239d9cee08SMichael Chan break; 1824c0c050c5SMichael Chan case SPEED_50000: 1825532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 1826f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 1827532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 1828532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 1829532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1830532262baSEdwin Peer } 18319d9cee08SMichael Chan break; 183238a21b34SDeepak Khungar case SPEED_100000: 1833532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 1834f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 1835532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 1836532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 1837532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1838532262baSEdwin Peer } 1839532262baSEdwin Peer break; 1840532262baSEdwin Peer case SPEED_200000: 1841532262baSEdwin Peer if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 1842532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 1843532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1844532262baSEdwin Peer } 1845c0c050c5SMichael Chan break; 1846c0c050c5SMichael Chan } 1847f00530bfSEdwin Peer 1848f00530bfSEdwin Peer if (!fw_speed) { 1849f00530bfSEdwin Peer netdev_err(dev, "unsupported speed!\n"); 1850f00530bfSEdwin Peer return -EINVAL; 1851f00530bfSEdwin Peer } 1852f00530bfSEdwin Peer 1853745b5c65SEdwin Peer if (link_info->req_link_speed == fw_speed && 1854745b5c65SEdwin Peer link_info->req_signal_mode == sig_mode && 1855745b5c65SEdwin Peer link_info->autoneg == 0) 1856745b5c65SEdwin Peer return -EALREADY; 1857745b5c65SEdwin Peer 1858f00530bfSEdwin Peer link_info->req_link_speed = fw_speed; 1859532262baSEdwin Peer link_info->req_signal_mode = sig_mode; 1860f00530bfSEdwin Peer link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 1861f00530bfSEdwin Peer link_info->autoneg = 0; 1862f00530bfSEdwin Peer link_info->advertising = 0; 1863532262baSEdwin Peer link_info->advertising_pam4 = 0; 1864f00530bfSEdwin Peer 1865f00530bfSEdwin Peer return 0; 1866c0c050c5SMichael Chan } 1867c0c050c5SMichael Chan 1868939f7f0cSMichael Chan u16 bnxt_get_fw_auto_link_speeds(u32 advertising) 1869c0c050c5SMichael Chan { 1870c0c050c5SMichael Chan u16 fw_speed_mask = 0; 1871c0c050c5SMichael Chan 1872c0c050c5SMichael Chan /* only support autoneg at speed 100, 1000, and 10000 */ 1873c0c050c5SMichael Chan if (advertising & (ADVERTISED_100baseT_Full | 1874c0c050c5SMichael Chan ADVERTISED_100baseT_Half)) { 1875c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 1876c0c050c5SMichael Chan } 1877c0c050c5SMichael Chan if (advertising & (ADVERTISED_1000baseT_Full | 1878c0c050c5SMichael Chan ADVERTISED_1000baseT_Half)) { 1879c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 1880c0c050c5SMichael Chan } 1881c0c050c5SMichael Chan if (advertising & ADVERTISED_10000baseT_Full) 1882c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 1883c0c050c5SMichael Chan 18841c49c421SMichael Chan if (advertising & ADVERTISED_40000baseCR4_Full) 18851c49c421SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18861c49c421SMichael Chan 1887c0c050c5SMichael Chan return fw_speed_mask; 1888c0c050c5SMichael Chan } 1889c0c050c5SMichael Chan 189000c04a92SMichael Chan static int bnxt_set_link_ksettings(struct net_device *dev, 189100c04a92SMichael Chan const struct ethtool_link_ksettings *lk_ksettings) 1892c0c050c5SMichael Chan { 1893c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1894c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 189500c04a92SMichael Chan const struct ethtool_link_settings *base = &lk_ksettings->base; 1896c0c050c5SMichael Chan bool set_pause = false; 189768515a18SMichael Chan u32 speed; 189800c04a92SMichael Chan int rc = 0; 1899c0c050c5SMichael Chan 1900c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 190100c04a92SMichael Chan return -EOPNOTSUPP; 1902c0c050c5SMichael Chan 1903e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 190400c04a92SMichael Chan if (base->autoneg == AUTONEG_ENABLE) { 1905532262baSEdwin Peer link_info->advertising = 0; 1906532262baSEdwin Peer link_info->advertising_pam4 = 0; 1907532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 190800c04a92SMichael Chan advertising); 1909532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 1910532262baSEdwin Peer lk_ksettings, advertising); 1911c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_SPEED; 1912532262baSEdwin Peer if (!link_info->advertising && !link_info->advertising_pam4) { 191393ed8117SMichael Chan link_info->advertising = link_info->support_auto_speeds; 1914532262baSEdwin Peer link_info->advertising_pam4 = 1915532262baSEdwin Peer link_info->support_pam4_auto_speeds; 1916532262baSEdwin Peer } 1917c0c050c5SMichael Chan /* any change to autoneg will cause link change, therefore the 1918c0c050c5SMichael Chan * driver should put back the original pause setting in autoneg 1919c0c050c5SMichael Chan */ 19209a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 1921c0c050c5SMichael Chan set_pause = true; 1922c0c050c5SMichael Chan } else { 192303efbec0SMichael Chan u8 phy_type = link_info->phy_type; 19249d9cee08SMichael Chan 192503efbec0SMichael Chan if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 192603efbec0SMichael Chan phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 192703efbec0SMichael Chan link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 192803efbec0SMichael Chan netdev_err(dev, "10GBase-T devices must autoneg\n"); 192903efbec0SMichael Chan rc = -EINVAL; 193003efbec0SMichael Chan goto set_setting_exit; 193103efbec0SMichael Chan } 193200c04a92SMichael Chan if (base->duplex == DUPLEX_HALF) { 1933c0c050c5SMichael Chan netdev_err(dev, "HALF DUPLEX is not supported!\n"); 1934c0c050c5SMichael Chan rc = -EINVAL; 1935c0c050c5SMichael Chan goto set_setting_exit; 1936c0c050c5SMichael Chan } 193700c04a92SMichael Chan speed = base->speed; 1938f00530bfSEdwin Peer rc = bnxt_force_link_speed(dev, speed); 1939745b5c65SEdwin Peer if (rc) { 1940745b5c65SEdwin Peer if (rc == -EALREADY) 1941745b5c65SEdwin Peer rc = 0; 19429d9cee08SMichael Chan goto set_setting_exit; 19439d9cee08SMichael Chan } 1944745b5c65SEdwin Peer } 1945c0c050c5SMichael Chan 1946c0c050c5SMichael Chan if (netif_running(dev)) 1947939f7f0cSMichael Chan rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 1948c0c050c5SMichael Chan 1949c0c050c5SMichael Chan set_setting_exit: 1950e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1951c0c050c5SMichael Chan return rc; 1952c0c050c5SMichael Chan } 1953c0c050c5SMichael Chan 19548b277589SMichael Chan static int bnxt_get_fecparam(struct net_device *dev, 19558b277589SMichael Chan struct ethtool_fecparam *fec) 19568b277589SMichael Chan { 19578b277589SMichael Chan struct bnxt *bp = netdev_priv(dev); 19588b277589SMichael Chan struct bnxt_link_info *link_info; 19598b277589SMichael Chan u8 active_fec; 19608b277589SMichael Chan u16 fec_cfg; 19618b277589SMichael Chan 19628b277589SMichael Chan link_info = &bp->link_info; 19638b277589SMichael Chan fec_cfg = link_info->fec_cfg; 19648b277589SMichael Chan active_fec = link_info->active_fec_sig_mode & 19658b277589SMichael Chan PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19668b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 19678b277589SMichael Chan fec->fec = ETHTOOL_FEC_NONE; 19688b277589SMichael Chan fec->active_fec = ETHTOOL_FEC_NONE; 19698b277589SMichael Chan return 0; 19708b277589SMichael Chan } 19718b277589SMichael Chan if (fec_cfg & BNXT_FEC_AUTONEG) 19728b277589SMichael Chan fec->fec |= ETHTOOL_FEC_AUTO; 19738b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19748b277589SMichael Chan fec->fec |= ETHTOOL_FEC_BASER; 19758b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 19768b277589SMichael Chan fec->fec |= ETHTOOL_FEC_RS; 19778b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 19788b277589SMichael Chan fec->fec |= ETHTOOL_FEC_LLRS; 19798b277589SMichael Chan 19808b277589SMichael Chan switch (active_fec) { 19818b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19828b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_BASER; 19838b277589SMichael Chan break; 19848b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19858b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19868b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19878b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_RS; 19888b277589SMichael Chan break; 19898b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19908b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19918b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_LLRS; 19928b277589SMichael Chan break; 199384d3c83eSSomnath Kotur case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 199484d3c83eSSomnath Kotur fec->active_fec |= ETHTOOL_FEC_OFF; 199584d3c83eSSomnath Kotur break; 19968b277589SMichael Chan } 19978b277589SMichael Chan return 0; 19988b277589SMichael Chan } 19998b277589SMichael Chan 2000c9ca5c3aSJakub Kicinski static void bnxt_get_fec_stats(struct net_device *dev, 2001c9ca5c3aSJakub Kicinski struct ethtool_fec_stats *fec_stats) 2002c9ca5c3aSJakub Kicinski { 2003c9ca5c3aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2004c9ca5c3aSJakub Kicinski u64 *rx; 2005c9ca5c3aSJakub Kicinski 2006c9ca5c3aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 2007c9ca5c3aSJakub Kicinski return; 2008c9ca5c3aSJakub Kicinski 2009c9ca5c3aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 2010c9ca5c3aSJakub Kicinski fec_stats->corrected_bits.total = 2011c9ca5c3aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 2012a802073dSJakub Kicinski 2013a802073dSJakub Kicinski if (bp->fw_rx_stats_ext_size <= BNXT_RX_STATS_EXT_NUM_LEGACY) 2014a802073dSJakub Kicinski return; 2015a802073dSJakub Kicinski 2016a802073dSJakub Kicinski fec_stats->corrected_blocks.total = 2017a802073dSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_corrected_blocks)); 2018a802073dSJakub Kicinski fec_stats->uncorrectable_blocks.total = 2019a802073dSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_uncorrectable_blocks)); 2020c9ca5c3aSJakub Kicinski } 2021c9ca5c3aSJakub Kicinski 2022ccd6a9dcSMichael Chan static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 2023ccd6a9dcSMichael Chan u32 fec) 2024ccd6a9dcSMichael Chan { 2025ccd6a9dcSMichael Chan u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 2026ccd6a9dcSMichael Chan 2027ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_BASER) 2028ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 2029ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_RS) 2030ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_RS_ON(link_info); 2031ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_LLRS) 2032ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_LLRS_ON; 2033ccd6a9dcSMichael Chan return fw_fec; 2034ccd6a9dcSMichael Chan } 2035ccd6a9dcSMichael Chan 2036ccd6a9dcSMichael Chan static int bnxt_set_fecparam(struct net_device *dev, 2037ccd6a9dcSMichael Chan struct ethtool_fecparam *fecparam) 2038ccd6a9dcSMichael Chan { 2039bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 2040ccd6a9dcSMichael Chan struct bnxt *bp = netdev_priv(dev); 2041ccd6a9dcSMichael Chan struct bnxt_link_info *link_info; 2042ccd6a9dcSMichael Chan u32 new_cfg, fec = fecparam->fec; 2043ccd6a9dcSMichael Chan u16 fec_cfg; 2044ccd6a9dcSMichael Chan int rc; 2045ccd6a9dcSMichael Chan 2046ccd6a9dcSMichael Chan link_info = &bp->link_info; 2047ccd6a9dcSMichael Chan fec_cfg = link_info->fec_cfg; 2048ccd6a9dcSMichael Chan if (fec_cfg & BNXT_FEC_NONE) 2049ccd6a9dcSMichael Chan return -EOPNOTSUPP; 2050ccd6a9dcSMichael Chan 2051ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_OFF) { 2052ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 2053ccd6a9dcSMichael Chan BNXT_FEC_ALL_OFF(link_info); 2054ccd6a9dcSMichael Chan goto apply_fec; 2055ccd6a9dcSMichael Chan } 2056ccd6a9dcSMichael Chan if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 2057ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 2058ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 2059ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 2060ccd6a9dcSMichael Chan return -EINVAL; 2061ccd6a9dcSMichael Chan 2062ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_AUTO) { 2063ccd6a9dcSMichael Chan if (!link_info->autoneg) 2064ccd6a9dcSMichael Chan return -EINVAL; 2065ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 2066ccd6a9dcSMichael Chan } else { 2067ccd6a9dcSMichael Chan new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 2068ccd6a9dcSMichael Chan } 2069ccd6a9dcSMichael Chan 2070ccd6a9dcSMichael Chan apply_fec: 2071bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 2072bbf33d1dSEdwin Peer if (rc) 2073bbf33d1dSEdwin Peer return rc; 2074bbf33d1dSEdwin Peer req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 2075bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2076ccd6a9dcSMichael Chan /* update current settings */ 2077ccd6a9dcSMichael Chan if (!rc) { 2078ccd6a9dcSMichael Chan mutex_lock(&bp->link_lock); 2079ccd6a9dcSMichael Chan bnxt_update_link(bp, false); 2080ccd6a9dcSMichael Chan mutex_unlock(&bp->link_lock); 2081ccd6a9dcSMichael Chan } 2082ccd6a9dcSMichael Chan return rc; 2083ccd6a9dcSMichael Chan } 2084ccd6a9dcSMichael Chan 2085c0c050c5SMichael Chan static void bnxt_get_pauseparam(struct net_device *dev, 2086c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2087c0c050c5SMichael Chan { 2088c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2089c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2090c0c050c5SMichael Chan 2091c0c050c5SMichael Chan if (BNXT_VF(bp)) 2092c0c050c5SMichael Chan return; 2093b763499eSMichael Chan epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20943c02d1bbSMichael Chan epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20953c02d1bbSMichael Chan epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 2096c0c050c5SMichael Chan } 2097c0c050c5SMichael Chan 2098423cffcfSJakub Kicinski static void bnxt_get_pause_stats(struct net_device *dev, 2099423cffcfSJakub Kicinski struct ethtool_pause_stats *epstat) 2100423cffcfSJakub Kicinski { 2101423cffcfSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2102423cffcfSJakub Kicinski u64 *rx, *tx; 2103423cffcfSJakub Kicinski 2104423cffcfSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 2105423cffcfSJakub Kicinski return; 2106423cffcfSJakub Kicinski 2107423cffcfSJakub Kicinski rx = bp->port_stats.sw_stats; 2108423cffcfSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 2109423cffcfSJakub Kicinski 2110423cffcfSJakub Kicinski epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 2111423cffcfSJakub Kicinski epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 2112423cffcfSJakub Kicinski } 2113423cffcfSJakub Kicinski 2114c0c050c5SMichael Chan static int bnxt_set_pauseparam(struct net_device *dev, 2115c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2116c0c050c5SMichael Chan { 2117c0c050c5SMichael Chan int rc = 0; 2118c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2119c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2120c0c050c5SMichael Chan 21219a3bc77eSMichael Chan if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 212275362a3fSMichael Chan return -EOPNOTSUPP; 2123c0c050c5SMichael Chan 2124a5390690SMichael Chan mutex_lock(&bp->link_lock); 2125c0c050c5SMichael Chan if (epause->autoneg) { 2126a5390690SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 2127a5390690SMichael Chan rc = -EINVAL; 2128a5390690SMichael Chan goto pause_exit; 2129a5390690SMichael Chan } 2130b763499eSMichael Chan 2131c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 21327c492a25SMichael Chan link_info->req_flow_ctrl = 0; 2133c0c050c5SMichael Chan } else { 2134c0c050c5SMichael Chan /* when transition from auto pause to force pause, 2135c0c050c5SMichael Chan * force a link change 2136c0c050c5SMichael Chan */ 2137c0c050c5SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 2138c0c050c5SMichael Chan link_info->force_link_chng = true; 2139c0c050c5SMichael Chan link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 2140c9ee9516SMichael Chan link_info->req_flow_ctrl = 0; 2141c0c050c5SMichael Chan } 2142c0c050c5SMichael Chan if (epause->rx_pause) 2143c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 2144c0c050c5SMichael Chan 2145c0c050c5SMichael Chan if (epause->tx_pause) 2146c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 2147c0c050c5SMichael Chan 2148a5390690SMichael Chan if (netif_running(dev)) 2149c0c050c5SMichael Chan rc = bnxt_hwrm_set_pause(bp); 2150a5390690SMichael Chan 2151a5390690SMichael Chan pause_exit: 2152163e9ef6SVasundhara Volam mutex_unlock(&bp->link_lock); 2153c0c050c5SMichael Chan return rc; 2154c0c050c5SMichael Chan } 2155c0c050c5SMichael Chan 2156c0c050c5SMichael Chan static u32 bnxt_get_link(struct net_device *dev) 2157c0c050c5SMichael Chan { 2158c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2159c0c050c5SMichael Chan 2160c0c050c5SMichael Chan /* TODO: handle MF, VF, driver close case */ 21610f5a4841SEdwin Peer return BNXT_LINK_IS_UP(bp); 2162c0c050c5SMichael Chan } 2163c0c050c5SMichael Chan 21644933f675SVasundhara Volam int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 21654933f675SVasundhara Volam struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 21664933f675SVasundhara Volam { 2167bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_output *resp; 2168bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_input *req; 21694933f675SVasundhara Volam int rc; 21704933f675SVasundhara Volam 21710ae0a779SVasundhara Volam if (BNXT_VF(bp)) 21720ae0a779SVasundhara Volam return -EOPNOTSUPP; 21730ae0a779SVasundhara Volam 2174bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 2175bbf33d1dSEdwin Peer if (rc) 2176bbf33d1dSEdwin Peer return rc; 2177bbf33d1dSEdwin Peer 2178bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 2179bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 21804933f675SVasundhara Volam if (!rc) 21814933f675SVasundhara Volam memcpy(nvm_dev_info, resp, sizeof(*resp)); 2182bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 21834933f675SVasundhara Volam return rc; 21844933f675SVasundhara Volam } 21854933f675SVasundhara Volam 2186b3b0ddd0SMichael Chan static void bnxt_print_admin_err(struct bnxt *bp) 2187b3b0ddd0SMichael Chan { 2188b3b0ddd0SMichael Chan netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 2189b3b0ddd0SMichael Chan } 2190b3b0ddd0SMichael Chan 21915b6ff128Svikas int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21924a5eaa2fSJakub Kicinski u16 ext, u16 *index, u32 *item_length, 21934a5eaa2fSJakub Kicinski u32 *data_length); 21944a5eaa2fSJakub Kicinski 21955b6ff128Svikas int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 219693ff3435SPavan Chebbi u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 219793ff3435SPavan Chebbi u32 dir_item_len, const u8 *data, 2198c0c050c5SMichael Chan size_t data_len) 2199c0c050c5SMichael Chan { 2200c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2201bbf33d1dSEdwin Peer struct hwrm_nvm_write_input *req; 2202c0c050c5SMichael Chan int rc; 2203c0c050c5SMichael Chan 2204bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 2205bbf33d1dSEdwin Peer if (rc) 2206bbf33d1dSEdwin Peer return rc; 2207c0c050c5SMichael Chan 220893ff3435SPavan Chebbi if (data_len && data) { 2209bbf33d1dSEdwin Peer dma_addr_t dma_handle; 2210bbf33d1dSEdwin Peer u8 *kmem; 2211c0c050c5SMichael Chan 2212bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 2213bbf33d1dSEdwin Peer if (!kmem) { 2214bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2215c0c050c5SMichael Chan return -ENOMEM; 221693ff3435SPavan Chebbi } 2217c0c050c5SMichael Chan 2218bbf33d1dSEdwin Peer req->dir_data_length = cpu_to_le32(data_len); 2219bbf33d1dSEdwin Peer 2220bbf33d1dSEdwin Peer memcpy(kmem, data, data_len); 2221bbf33d1dSEdwin Peer req->host_src_addr = cpu_to_le64(dma_handle); 2222bbf33d1dSEdwin Peer } 2223bbf33d1dSEdwin Peer 2224bce9a0b7SEdwin Peer hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 2225bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(dir_type); 2226bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(dir_ordinal); 2227bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(dir_ext); 2228bbf33d1dSEdwin Peer req->dir_attr = cpu_to_le16(dir_attr); 2229bbf33d1dSEdwin Peer req->dir_item_length = cpu_to_le32(dir_item_len); 2230bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2231c0c050c5SMichael Chan 2232d4f1420dSMichael Chan if (rc == -EACCES) 2233b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2234c0c050c5SMichael Chan return rc; 2235c0c050c5SMichael Chan } 2236c0c050c5SMichael Chan 22378f6c5e4dSEdwin Peer int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 223895fec034SEdwin Peer u8 self_reset, u8 flags) 2239d2d6318cSRob Swindell { 22407c675421SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 2241bbf33d1dSEdwin Peer struct hwrm_fw_reset_input *req; 22427c675421SVasundhara Volam int rc; 2243d2d6318cSRob Swindell 2244892a662fSEdwin Peer if (!bnxt_hwrm_reset_permitted(bp)) { 2245892a662fSEdwin Peer netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 2246892a662fSEdwin Peer return -EPERM; 2247892a662fSEdwin Peer } 2248892a662fSEdwin Peer 2249bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 2250bbf33d1dSEdwin Peer if (rc) 2251bbf33d1dSEdwin Peer return rc; 2252d2d6318cSRob Swindell 2253bbf33d1dSEdwin Peer req->embedded_proc_type = proc_type; 2254bbf33d1dSEdwin Peer req->selfrst_status = self_reset; 2255bbf33d1dSEdwin Peer req->flags = flags; 225695fec034SEdwin Peer 22578cec0940SEdwin Peer if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 2258bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 22598cec0940SEdwin Peer } else { 2260bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 226195fec034SEdwin Peer if (rc == -EACCES) 226295fec034SEdwin Peer bnxt_print_admin_err(bp); 22638cec0940SEdwin Peer } 226495fec034SEdwin Peer return rc; 226595fec034SEdwin Peer } 226695fec034SEdwin Peer 226794f17e89SEdwin Peer static int bnxt_firmware_reset(struct net_device *dev, 226894f17e89SEdwin Peer enum bnxt_nvm_directory_type dir_type) 226995fec034SEdwin Peer { 227095fec034SEdwin Peer u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 227195fec034SEdwin Peer u8 proc_type, flags = 0; 227295fec034SEdwin Peer 2273d2d6318cSRob Swindell /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 2274d2d6318cSRob Swindell /* (e.g. when firmware isn't already running) */ 2275d2d6318cSRob Swindell switch (dir_type) { 2276d2d6318cSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 2277d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE: 2278d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE_2: 227995fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 2280d2d6318cSRob Swindell /* Self-reset ChiMP upon next PCIe reset: */ 228195fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2282d2d6318cSRob Swindell break; 2283d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_FW: 2284d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 228595fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 228608141e0bSRob Swindell /* Self-reset APE upon next PCIe reset: */ 228795fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2288d2d6318cSRob Swindell break; 2289d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_FW: 2290d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 229195fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 2292d2d6318cSRob Swindell break; 2293d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_FW: 2294d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 229595fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 2296d2d6318cSRob Swindell break; 2297d2d6318cSRob Swindell default: 2298d2d6318cSRob Swindell return -EINVAL; 2299d2d6318cSRob Swindell } 2300d2d6318cSRob Swindell 230195fec034SEdwin Peer return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 2302d2d6318cSRob Swindell } 2303d2d6318cSRob Swindell 230494f17e89SEdwin Peer static int bnxt_firmware_reset_chip(struct net_device *dev) 230594f17e89SEdwin Peer { 230694f17e89SEdwin Peer struct bnxt *bp = netdev_priv(dev); 230794f17e89SEdwin Peer u8 flags = 0; 230894f17e89SEdwin Peer 230994f17e89SEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 231094f17e89SEdwin Peer flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 231194f17e89SEdwin Peer 231294f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, 231394f17e89SEdwin Peer FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 231494f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 231594f17e89SEdwin Peer flags); 231694f17e89SEdwin Peer } 231794f17e89SEdwin Peer 231894f17e89SEdwin Peer static int bnxt_firmware_reset_ap(struct net_device *dev) 231994f17e89SEdwin Peer { 232094f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 232194f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 232294f17e89SEdwin Peer 0); 232394f17e89SEdwin Peer } 232494f17e89SEdwin Peer 2325c0c050c5SMichael Chan static int bnxt_flash_firmware(struct net_device *dev, 2326c0c050c5SMichael Chan u16 dir_type, 2327c0c050c5SMichael Chan const u8 *fw_data, 2328c0c050c5SMichael Chan size_t fw_size) 2329c0c050c5SMichael Chan { 2330c0c050c5SMichael Chan int rc = 0; 2331c0c050c5SMichael Chan u16 code_type; 2332c0c050c5SMichael Chan u32 stored_crc; 2333c0c050c5SMichael Chan u32 calculated_crc; 2334c0c050c5SMichael Chan struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 2335c0c050c5SMichael Chan 2336c0c050c5SMichael Chan switch (dir_type) { 2337c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2338c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2339c0c050c5SMichael Chan code_type = CODE_BOOT; 2340c0c050c5SMichael Chan break; 234193e0b4feSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 234293e0b4feSRob Swindell code_type = CODE_CHIMP_PATCH; 234393e0b4feSRob Swindell break; 23442731d70fSRob Swindell case BNX_DIR_TYPE_APE_FW: 23452731d70fSRob Swindell code_type = CODE_MCTP_PASSTHRU; 23462731d70fSRob Swindell break; 234793e0b4feSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 234893e0b4feSRob Swindell code_type = CODE_APE_PATCH; 234993e0b4feSRob Swindell break; 235093e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_FW: 235193e0b4feSRob Swindell code_type = CODE_KONG_FW; 235293e0b4feSRob Swindell break; 235393e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 235493e0b4feSRob Swindell code_type = CODE_KONG_PATCH; 235593e0b4feSRob Swindell break; 235693e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 235793e0b4feSRob Swindell code_type = CODE_BONO_FW; 235893e0b4feSRob Swindell break; 235993e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 236093e0b4feSRob Swindell code_type = CODE_BONO_PATCH; 236193e0b4feSRob Swindell break; 2362c0c050c5SMichael Chan default: 2363c0c050c5SMichael Chan netdev_err(dev, "Unsupported directory entry type: %u\n", 2364c0c050c5SMichael Chan dir_type); 2365c0c050c5SMichael Chan return -EINVAL; 2366c0c050c5SMichael Chan } 2367c0c050c5SMichael Chan if (fw_size < sizeof(struct bnxt_fw_header)) { 2368c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware file size: %u\n", 2369c0c050c5SMichael Chan (unsigned int)fw_size); 2370c0c050c5SMichael Chan return -EINVAL; 2371c0c050c5SMichael Chan } 2372c0c050c5SMichael Chan if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 2373c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware signature: %08X\n", 2374c0c050c5SMichael Chan le32_to_cpu(header->signature)); 2375c0c050c5SMichael Chan return -EINVAL; 2376c0c050c5SMichael Chan } 2377c0c050c5SMichael Chan if (header->code_type != code_type) { 2378c0c050c5SMichael Chan netdev_err(dev, "Expected firmware type: %d, read: %d\n", 2379c0c050c5SMichael Chan code_type, header->code_type); 2380c0c050c5SMichael Chan return -EINVAL; 2381c0c050c5SMichael Chan } 2382c0c050c5SMichael Chan if (header->device != DEVICE_CUMULUS_FAMILY) { 2383c0c050c5SMichael Chan netdev_err(dev, "Expected firmware device family %d, read: %d\n", 2384c0c050c5SMichael Chan DEVICE_CUMULUS_FAMILY, header->device); 2385c0c050c5SMichael Chan return -EINVAL; 2386c0c050c5SMichael Chan } 2387c0c050c5SMichael Chan /* Confirm the CRC32 checksum of the file: */ 2388c0c050c5SMichael Chan stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 2389c0c050c5SMichael Chan sizeof(stored_crc))); 2390c0c050c5SMichael Chan calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 2391c0c050c5SMichael Chan if (calculated_crc != stored_crc) { 2392c0c050c5SMichael Chan netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 2393c0c050c5SMichael Chan (unsigned long)stored_crc, 2394c0c050c5SMichael Chan (unsigned long)calculated_crc); 2395c0c050c5SMichael Chan return -EINVAL; 2396c0c050c5SMichael Chan } 2397c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2398bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 2399d2d6318cSRob Swindell if (rc == 0) /* Firmware update successful */ 2400d2d6318cSRob Swindell rc = bnxt_firmware_reset(dev, dir_type); 2401d2d6318cSRob Swindell 2402c0c050c5SMichael Chan return rc; 2403c0c050c5SMichael Chan } 2404c0c050c5SMichael Chan 24055ac67d8bSRob Swindell static int bnxt_flash_microcode(struct net_device *dev, 24065ac67d8bSRob Swindell u16 dir_type, 24075ac67d8bSRob Swindell const u8 *fw_data, 24085ac67d8bSRob Swindell size_t fw_size) 24095ac67d8bSRob Swindell { 24105ac67d8bSRob Swindell struct bnxt_ucode_trailer *trailer; 24115ac67d8bSRob Swindell u32 calculated_crc; 24125ac67d8bSRob Swindell u32 stored_crc; 24135ac67d8bSRob Swindell int rc = 0; 24145ac67d8bSRob Swindell 24155ac67d8bSRob Swindell if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 24165ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode file size: %u\n", 24175ac67d8bSRob Swindell (unsigned int)fw_size); 24185ac67d8bSRob Swindell return -EINVAL; 24195ac67d8bSRob Swindell } 24205ac67d8bSRob Swindell trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 24215ac67d8bSRob Swindell sizeof(*trailer))); 24225ac67d8bSRob Swindell if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 24235ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 24245ac67d8bSRob Swindell le32_to_cpu(trailer->sig)); 24255ac67d8bSRob Swindell return -EINVAL; 24265ac67d8bSRob Swindell } 24275ac67d8bSRob Swindell if (le16_to_cpu(trailer->dir_type) != dir_type) { 24285ac67d8bSRob Swindell netdev_err(dev, "Expected microcode type: %d, read: %d\n", 24295ac67d8bSRob Swindell dir_type, le16_to_cpu(trailer->dir_type)); 24305ac67d8bSRob Swindell return -EINVAL; 24315ac67d8bSRob Swindell } 24325ac67d8bSRob Swindell if (le16_to_cpu(trailer->trailer_length) < 24335ac67d8bSRob Swindell sizeof(struct bnxt_ucode_trailer)) { 24345ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer length: %d\n", 24355ac67d8bSRob Swindell le16_to_cpu(trailer->trailer_length)); 24365ac67d8bSRob Swindell return -EINVAL; 24375ac67d8bSRob Swindell } 24385ac67d8bSRob Swindell 24395ac67d8bSRob Swindell /* Confirm the CRC32 checksum of the file: */ 24405ac67d8bSRob Swindell stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 24415ac67d8bSRob Swindell sizeof(stored_crc))); 24425ac67d8bSRob Swindell calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 24435ac67d8bSRob Swindell if (calculated_crc != stored_crc) { 24445ac67d8bSRob Swindell netdev_err(dev, 24455ac67d8bSRob Swindell "CRC32 (%08lX) does not match calculated: %08lX\n", 24465ac67d8bSRob Swindell (unsigned long)stored_crc, 24475ac67d8bSRob Swindell (unsigned long)calculated_crc); 24485ac67d8bSRob Swindell return -EINVAL; 24495ac67d8bSRob Swindell } 24505ac67d8bSRob Swindell rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2451bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 24525ac67d8bSRob Swindell 24535ac67d8bSRob Swindell return rc; 24545ac67d8bSRob Swindell } 24555ac67d8bSRob Swindell 2456c0c050c5SMichael Chan static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 2457c0c050c5SMichael Chan { 2458c0c050c5SMichael Chan switch (dir_type) { 2459c0c050c5SMichael Chan case BNX_DIR_TYPE_CHIMP_PATCH: 2460c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2461c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2462c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_FW: 2463c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_PATCH: 2464c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_FW: 2465c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_PATCH: 246693e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 246793e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 2468c0c050c5SMichael Chan return true; 2469c0c050c5SMichael Chan } 2470c0c050c5SMichael Chan 2471c0c050c5SMichael Chan return false; 2472c0c050c5SMichael Chan } 2473c0c050c5SMichael Chan 24745ac67d8bSRob Swindell static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 2475c0c050c5SMichael Chan { 2476c0c050c5SMichael Chan switch (dir_type) { 2477c0c050c5SMichael Chan case BNX_DIR_TYPE_AVS: 2478c0c050c5SMichael Chan case BNX_DIR_TYPE_EXP_ROM_MBA: 2479c0c050c5SMichael Chan case BNX_DIR_TYPE_PCIE: 2480c0c050c5SMichael Chan case BNX_DIR_TYPE_TSCF_UCODE: 2481c0c050c5SMichael Chan case BNX_DIR_TYPE_EXT_PHY: 2482c0c050c5SMichael Chan case BNX_DIR_TYPE_CCM: 2483c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT: 2484c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 2485c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 2486c0c050c5SMichael Chan return true; 2487c0c050c5SMichael Chan } 2488c0c050c5SMichael Chan 2489c0c050c5SMichael Chan return false; 2490c0c050c5SMichael Chan } 2491c0c050c5SMichael Chan 2492c0c050c5SMichael Chan static bool bnxt_dir_type_is_executable(u16 dir_type) 2493c0c050c5SMichael Chan { 2494c0c050c5SMichael Chan return bnxt_dir_type_is_ape_bin_format(dir_type) || 24955ac67d8bSRob Swindell bnxt_dir_type_is_other_exec_format(dir_type); 2496c0c050c5SMichael Chan } 2497c0c050c5SMichael Chan 2498c0c050c5SMichael Chan static int bnxt_flash_firmware_from_file(struct net_device *dev, 2499c0c050c5SMichael Chan u16 dir_type, 2500c0c050c5SMichael Chan const char *filename) 2501c0c050c5SMichael Chan { 2502c0c050c5SMichael Chan const struct firmware *fw; 2503c0c050c5SMichael Chan int rc; 2504c0c050c5SMichael Chan 2505c0c050c5SMichael Chan rc = request_firmware(&fw, filename, &dev->dev); 2506c0c050c5SMichael Chan if (rc != 0) { 2507c0c050c5SMichael Chan netdev_err(dev, "Error %d requesting firmware file: %s\n", 2508c0c050c5SMichael Chan rc, filename); 2509c0c050c5SMichael Chan return rc; 2510c0c050c5SMichael Chan } 2511ba425800SJason Yan if (bnxt_dir_type_is_ape_bin_format(dir_type)) 2512c0c050c5SMichael Chan rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 2513ba425800SJason Yan else if (bnxt_dir_type_is_other_exec_format(dir_type)) 25145ac67d8bSRob Swindell rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 2515c0c050c5SMichael Chan else 2516c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2517bbf33d1dSEdwin Peer 0, 0, 0, fw->data, fw->size); 2518c0c050c5SMichael Chan release_firmware(fw); 2519c0c050c5SMichael Chan return rc; 2520c0c050c5SMichael Chan } 2521c0c050c5SMichael Chan 2522ab0bed4bSKalesh AP #define MSG_INTEGRITY_ERR "PKG install error : Data integrity on NVM" 2523ab0bed4bSKalesh AP #define MSG_INVALID_PKG "PKG install error : Invalid package" 2524ab0bed4bSKalesh AP #define MSG_AUTHENTICATION_ERR "PKG install error : Authentication error" 2525ab0bed4bSKalesh AP #define MSG_INVALID_DEV "PKG install error : Invalid device" 2526ab0bed4bSKalesh AP #define MSG_INTERNAL_ERR "PKG install error : Internal error" 2527ab0bed4bSKalesh AP #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" 2528ab0bed4bSKalesh AP #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" 252945034224SVikas Gupta #define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" 2530ab0bed4bSKalesh AP #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" 2531ab0bed4bSKalesh AP #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" 2532ab0bed4bSKalesh AP 2533ab0bed4bSKalesh AP static int nvm_update_err_to_stderr(struct net_device *dev, u8 result, 2534ab0bed4bSKalesh AP struct netlink_ext_ack *extack) 2535ab0bed4bSKalesh AP { 2536ab0bed4bSKalesh AP switch (result) { 2537ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER: 2538ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER: 2539ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR: 2540ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR: 2541ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND: 2542ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED: 2543ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INTEGRITY_ERR); 2544ab0bed4bSKalesh AP return -EINVAL; 2545ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE: 2546ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER: 2547ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE: 2548ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM: 2549ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH: 2550ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST: 2551ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER: 2552ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM: 2553ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM: 2554ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH: 2555ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE: 2556ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM: 2557ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM: 2558ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_PKG); 2559ab0bed4bSKalesh AP return -ENOPKG; 2560ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR: 2561ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_AUTHENTICATION_ERR); 2562ab0bed4bSKalesh AP return -EPERM; 2563ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV: 2564ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID: 2565ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR: 2566ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID: 2567ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM: 2568ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_DEV); 2569ab0bed4bSKalesh AP return -EOPNOTSUPP; 2570ab0bed4bSKalesh AP default: 2571ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INTERNAL_ERR); 2572ab0bed4bSKalesh AP return -EIO; 2573ab0bed4bSKalesh AP } 2574ab0bed4bSKalesh AP } 2575ab0bed4bSKalesh AP 2576a86b313eSMichael Chan #define BNXT_PKG_DMA_SIZE 0x40000 2577a86b313eSMichael Chan #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 2578a86b313eSMichael Chan #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 2579a86b313eSMichael Chan 258045034224SVikas Gupta static int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, 258145034224SVikas Gupta struct netlink_ext_ack *extack) 258245034224SVikas Gupta { 258345034224SVikas Gupta u32 item_len; 258445034224SVikas Gupta int rc; 258545034224SVikas Gupta 258645034224SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 258745034224SVikas Gupta BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, 258845034224SVikas Gupta &item_len, NULL); 258945034224SVikas Gupta if (rc) { 259045034224SVikas Gupta BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 259145034224SVikas Gupta return rc; 259245034224SVikas Gupta } 259345034224SVikas Gupta 259445034224SVikas Gupta if (fw_size > item_len) { 259545034224SVikas Gupta rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE, 259645034224SVikas Gupta BNX_DIR_ORDINAL_FIRST, 0, 1, 259745034224SVikas Gupta round_up(fw_size, 4096), NULL, 0); 259845034224SVikas Gupta if (rc) { 259945034224SVikas Gupta BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); 260045034224SVikas Gupta return rc; 260145034224SVikas Gupta } 260245034224SVikas Gupta } 260345034224SVikas Gupta return 0; 260445034224SVikas Gupta } 260545034224SVikas Gupta 2606b44cfd4fSJacob Keller int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 2607ab0bed4bSKalesh AP u32 install_type, struct netlink_ext_ack *extack) 2608c0c050c5SMichael Chan { 2609bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_input *install; 2610bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_output *resp; 2611bbf33d1dSEdwin Peer struct hwrm_nvm_modify_input *modify; 2612a9094ba6SMichael Chan struct bnxt *bp = netdev_priv(dev); 26131432c3f6SPavan Chebbi bool defrag_attempted = false; 2614a9094ba6SMichael Chan dma_addr_t dma_handle; 2615a9094ba6SMichael Chan u8 *kmem = NULL; 2616a86b313eSMichael Chan u32 modify_len; 26175ac67d8bSRob Swindell u32 item_len; 26188e42aef0SKalesh AP u8 cmd_err; 26195ac67d8bSRob Swindell u16 index; 2620bbf33d1dSEdwin Peer int rc; 26215ac67d8bSRob Swindell 262245034224SVikas Gupta /* resize before flashing larger image than available space */ 262345034224SVikas Gupta rc = bnxt_resize_update_entry(dev, fw->size, extack); 262445034224SVikas Gupta if (rc) 262545034224SVikas Gupta return rc; 262645034224SVikas Gupta 26275ac67d8bSRob Swindell bnxt_hwrm_fw_set_time(bp); 26285ac67d8bSRob Swindell 2629bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 2630bbf33d1dSEdwin Peer if (rc) 2631bbf33d1dSEdwin Peer return rc; 2632a9094ba6SMichael Chan 2633a86b313eSMichael Chan /* Try allocating a large DMA buffer first. Older fw will 2634a86b313eSMichael Chan * cause excessive NVRAM erases when using small blocks. 2635a86b313eSMichael Chan */ 2636a86b313eSMichael Chan modify_len = roundup_pow_of_two(fw->size); 2637a86b313eSMichael Chan modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 2638a86b313eSMichael Chan while (1) { 2639bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 2640a86b313eSMichael Chan if (!kmem && modify_len > PAGE_SIZE) 2641a86b313eSMichael Chan modify_len /= 2; 2642a86b313eSMichael Chan else 2643a86b313eSMichael Chan break; 2644a86b313eSMichael Chan } 2645bbf33d1dSEdwin Peer if (!kmem) { 2646bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2647a9094ba6SMichael Chan return -ENOMEM; 2648bbf33d1dSEdwin Peer } 2649a9094ba6SMichael Chan 2650bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 2651bbf33d1dSEdwin Peer if (rc) { 2652bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2653bbf33d1dSEdwin Peer return rc; 2654bbf33d1dSEdwin Peer } 2655a9094ba6SMichael Chan 2656bce9a0b7SEdwin Peer hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 2657bce9a0b7SEdwin Peer hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 2658bbf33d1dSEdwin Peer 2659bbf33d1dSEdwin Peer hwrm_req_hold(bp, modify); 2660bbf33d1dSEdwin Peer modify->host_src_addr = cpu_to_le64(dma_handle); 2661bbf33d1dSEdwin Peer 2662bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, install); 2663a9094ba6SMichael Chan if ((install_type & 0xffff) == 0) 2664a9094ba6SMichael Chan install_type >>= 16; 2665bbf33d1dSEdwin Peer install->install_type = cpu_to_le32(install_type); 2666a9094ba6SMichael Chan 26672e5fb428SPavan Chebbi do { 2668a86b313eSMichael Chan u32 copied = 0, len = modify_len; 2669a86b313eSMichael Chan 267095ec1f47SVasundhara Volam rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 26712e5fb428SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 26722e5fb428SPavan Chebbi BNX_DIR_EXT_NONE, 267395ec1f47SVasundhara Volam &index, &item_len, NULL); 267495ec1f47SVasundhara Volam if (rc) { 2675ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 26762e5fb428SPavan Chebbi break; 26775ac67d8bSRob Swindell } 26785ac67d8bSRob Swindell if (fw->size > item_len) { 2679ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_SPACE_ERR); 26805ac67d8bSRob Swindell rc = -EFBIG; 26812e5fb428SPavan Chebbi break; 26822e5fb428SPavan Chebbi } 26832e5fb428SPavan Chebbi 2684bbf33d1dSEdwin Peer modify->dir_idx = cpu_to_le16(index); 26855ac67d8bSRob Swindell 2686a86b313eSMichael Chan if (fw->size > modify_len) 2687bbf33d1dSEdwin Peer modify->flags = BNXT_NVM_MORE_FLAG; 2688a86b313eSMichael Chan while (copied < fw->size) { 2689a86b313eSMichael Chan u32 balance = fw->size - copied; 2690a86b313eSMichael Chan 2691a86b313eSMichael Chan if (balance <= modify_len) { 2692a86b313eSMichael Chan len = balance; 2693a86b313eSMichael Chan if (copied) 2694bbf33d1dSEdwin Peer modify->flags |= BNXT_NVM_LAST_FLAG; 2695a86b313eSMichael Chan } 2696a86b313eSMichael Chan memcpy(kmem, fw->data + copied, len); 2697bbf33d1dSEdwin Peer modify->len = cpu_to_le32(len); 2698bbf33d1dSEdwin Peer modify->offset = cpu_to_le32(copied); 2699bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, modify); 270022630e28SEdwin Peer if (rc) 2701a86b313eSMichael Chan goto pkg_abort; 2702a86b313eSMichael Chan copied += len; 2703a86b313eSMichael Chan } 2704bbf33d1dSEdwin Peer 2705bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 27068e42aef0SKalesh AP if (!rc) 27078e42aef0SKalesh AP break; 2708cb4d1d62SKshitij Soni 27091432c3f6SPavan Chebbi if (defrag_attempted) { 27101432c3f6SPavan Chebbi /* We have tried to defragment already in the previous 27111432c3f6SPavan Chebbi * iteration. Return with the result for INSTALL_UPDATE 27121432c3f6SPavan Chebbi */ 27131432c3f6SPavan Chebbi break; 27141432c3f6SPavan Chebbi } 27151432c3f6SPavan Chebbi 27168e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 27178e42aef0SKalesh AP 27188e42aef0SKalesh AP switch (cmd_err) { 271954ff1e3eSKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: 2720ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_ANTI_ROLLBACK_ERR); 272154ff1e3eSKalesh AP rc = -EALREADY; 272254ff1e3eSKalesh AP break; 27238e42aef0SKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: 2724bbf33d1dSEdwin Peer install->flags = 27252e5fb428SPavan Chebbi cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 27262e5fb428SPavan Chebbi 2727bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 27288e42aef0SKalesh AP if (!rc) 27298e42aef0SKalesh AP break; 27301432c3f6SPavan Chebbi 27318e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 27328e42aef0SKalesh AP 27338e42aef0SKalesh AP if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 27341432c3f6SPavan Chebbi /* FW has cleared NVM area, driver will create 27351432c3f6SPavan Chebbi * UPDATE directory and try the flash again 27361432c3f6SPavan Chebbi */ 27371432c3f6SPavan Chebbi defrag_attempted = true; 2738bbf33d1dSEdwin Peer install->flags = 0; 2739bbf33d1dSEdwin Peer rc = bnxt_flash_nvram(bp->dev, 27401432c3f6SPavan Chebbi BNX_DIR_TYPE_UPDATE, 27411432c3f6SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 2742bbf33d1dSEdwin Peer 0, 0, item_len, NULL, 0); 27438e42aef0SKalesh AP if (!rc) 27448e42aef0SKalesh AP break; 27451432c3f6SPavan Chebbi } 27468e42aef0SKalesh AP fallthrough; 27478e42aef0SKalesh AP default: 2748ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_GENERIC_FAILURE_ERR); 2749dd2ebf34SVasundhara Volam } 27501432c3f6SPavan Chebbi } while (defrag_attempted && !rc); 27515ac67d8bSRob Swindell 2752a86b313eSMichael Chan pkg_abort: 2753bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2754bbf33d1dSEdwin Peer hwrm_req_drop(bp, install); 2755bbf33d1dSEdwin Peer 2756bbf33d1dSEdwin Peer if (resp->result) { 27575ac67d8bSRob Swindell netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 2758bbf33d1dSEdwin Peer (s8)resp->result, (int)resp->problem_item); 2759ab0bed4bSKalesh AP rc = nvm_update_err_to_stderr(dev, resp->result, extack); 27605ac67d8bSRob Swindell } 276122630e28SEdwin Peer if (rc == -EACCES) 2762b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2763cb4d1d62SKshitij Soni return rc; 2764c0c050c5SMichael Chan } 2765c0c050c5SMichael Chan 2766b44cfd4fSJacob Keller static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 2767ab0bed4bSKalesh AP u32 install_type, struct netlink_ext_ack *extack) 2768b44cfd4fSJacob Keller { 2769b44cfd4fSJacob Keller const struct firmware *fw; 2770b44cfd4fSJacob Keller int rc; 2771b44cfd4fSJacob Keller 2772b44cfd4fSJacob Keller rc = request_firmware(&fw, filename, &dev->dev); 2773b44cfd4fSJacob Keller if (rc != 0) { 2774b44cfd4fSJacob Keller netdev_err(dev, "PKG error %d requesting file: %s\n", 2775b44cfd4fSJacob Keller rc, filename); 2776b44cfd4fSJacob Keller return rc; 2777b44cfd4fSJacob Keller } 2778b44cfd4fSJacob Keller 2779ab0bed4bSKalesh AP rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type, extack); 2780b44cfd4fSJacob Keller 2781b44cfd4fSJacob Keller release_firmware(fw); 2782b44cfd4fSJacob Keller 2783b44cfd4fSJacob Keller return rc; 2784b44cfd4fSJacob Keller } 2785b44cfd4fSJacob Keller 2786c0c050c5SMichael Chan static int bnxt_flash_device(struct net_device *dev, 2787c0c050c5SMichael Chan struct ethtool_flash *flash) 2788c0c050c5SMichael Chan { 2789c0c050c5SMichael Chan if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 2790c0c050c5SMichael Chan netdev_err(dev, "flashdev not supported from a virtual function\n"); 2791c0c050c5SMichael Chan return -EINVAL; 2792c0c050c5SMichael Chan } 2793c0c050c5SMichael Chan 27945ac67d8bSRob Swindell if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 27955ac67d8bSRob Swindell flash->region > 0xffff) 27965ac67d8bSRob Swindell return bnxt_flash_package_from_file(dev, flash->data, 2797ab0bed4bSKalesh AP flash->region, NULL); 2798c0c050c5SMichael Chan 2799c0c050c5SMichael Chan return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 2800c0c050c5SMichael Chan } 2801c0c050c5SMichael Chan 2802c0c050c5SMichael Chan static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 2803c0c050c5SMichael Chan { 2804bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_output *output; 2805bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_input *req; 2806c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2807c0c050c5SMichael Chan int rc; 2808c0c050c5SMichael Chan 2809bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 2810bbf33d1dSEdwin Peer if (rc) 2811bbf33d1dSEdwin Peer return rc; 2812c0c050c5SMichael Chan 2813bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2814bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2815c0c050c5SMichael Chan if (!rc) { 2816c0c050c5SMichael Chan *entries = le32_to_cpu(output->entries); 2817c0c050c5SMichael Chan *length = le32_to_cpu(output->entry_length); 2818c0c050c5SMichael Chan } 2819bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2820c0c050c5SMichael Chan return rc; 2821c0c050c5SMichael Chan } 2822c0c050c5SMichael Chan 2823c0c050c5SMichael Chan static int bnxt_get_eeprom_len(struct net_device *dev) 2824c0c050c5SMichael Chan { 28254cebbacaSMichael Chan struct bnxt *bp = netdev_priv(dev); 28264cebbacaSMichael Chan 28274cebbacaSMichael Chan if (BNXT_VF(bp)) 28284cebbacaSMichael Chan return 0; 28294cebbacaSMichael Chan 2830c0c050c5SMichael Chan /* The -1 return value allows the entire 32-bit range of offsets to be 2831c0c050c5SMichael Chan * passed via the ethtool command-line utility. 2832c0c050c5SMichael Chan */ 2833c0c050c5SMichael Chan return -1; 2834c0c050c5SMichael Chan } 2835c0c050c5SMichael Chan 2836c0c050c5SMichael Chan static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 2837c0c050c5SMichael Chan { 2838c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2839c0c050c5SMichael Chan int rc; 2840c0c050c5SMichael Chan u32 dir_entries; 2841c0c050c5SMichael Chan u32 entry_length; 2842c0c050c5SMichael Chan u8 *buf; 2843c0c050c5SMichael Chan size_t buflen; 2844c0c050c5SMichael Chan dma_addr_t dma_handle; 2845bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_entries_input *req; 2846c0c050c5SMichael Chan 2847c0c050c5SMichael Chan rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 2848c0c050c5SMichael Chan if (rc != 0) 2849c0c050c5SMichael Chan return rc; 2850c0c050c5SMichael Chan 2851dbbfa96aSVasundhara Volam if (!dir_entries || !entry_length) 2852dbbfa96aSVasundhara Volam return -EIO; 2853dbbfa96aSVasundhara Volam 2854c0c050c5SMichael Chan /* Insert 2 bytes of directory info (count and size of entries) */ 2855c0c050c5SMichael Chan if (len < 2) 2856c0c050c5SMichael Chan return -EINVAL; 2857c0c050c5SMichael Chan 2858c0c050c5SMichael Chan *data++ = dir_entries; 2859c0c050c5SMichael Chan *data++ = entry_length; 2860c0c050c5SMichael Chan len -= 2; 2861c0c050c5SMichael Chan memset(data, 0xff, len); 2862c0c050c5SMichael Chan 2863bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 2864bbf33d1dSEdwin Peer if (rc) 2865bbf33d1dSEdwin Peer return rc; 2866bbf33d1dSEdwin Peer 2867c0c050c5SMichael Chan buflen = dir_entries * entry_length; 2868bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 2869c0c050c5SMichael Chan if (!buf) { 2870bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2871c0c050c5SMichael Chan return -ENOMEM; 2872c0c050c5SMichael Chan } 2873bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2874bbf33d1dSEdwin Peer 2875bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2876bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2877c0c050c5SMichael Chan if (rc == 0) 2878c0c050c5SMichael Chan memcpy(data, buf, len > buflen ? buflen : len); 2879bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2880c0c050c5SMichael Chan return rc; 2881c0c050c5SMichael Chan } 2882c0c050c5SMichael Chan 28835b6ff128Svikas int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 2884c0c050c5SMichael Chan u32 length, u8 *data) 2885c0c050c5SMichael Chan { 2886c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2887c0c050c5SMichael Chan int rc; 2888c0c050c5SMichael Chan u8 *buf; 2889c0c050c5SMichael Chan dma_addr_t dma_handle; 2890bbf33d1dSEdwin Peer struct hwrm_nvm_read_input *req; 2891c0c050c5SMichael Chan 2892e0ad8fc5SMichael Chan if (!length) 2893e0ad8fc5SMichael Chan return -EINVAL; 2894e0ad8fc5SMichael Chan 2895bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 2896bbf33d1dSEdwin Peer if (rc) 2897bbf33d1dSEdwin Peer return rc; 2898bbf33d1dSEdwin Peer 2899bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 2900c0c050c5SMichael Chan if (!buf) { 2901bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2902c0c050c5SMichael Chan return -ENOMEM; 2903c0c050c5SMichael Chan } 2904c0c050c5SMichael Chan 2905bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2906bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2907bbf33d1dSEdwin Peer req->offset = cpu_to_le32(offset); 2908bbf33d1dSEdwin Peer req->len = cpu_to_le32(length); 2909bbf33d1dSEdwin Peer 2910bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2911bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2912c0c050c5SMichael Chan if (rc == 0) 2913c0c050c5SMichael Chan memcpy(data, buf, length); 2914bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2915c0c050c5SMichael Chan return rc; 2916c0c050c5SMichael Chan } 2917c0c050c5SMichael Chan 29185b6ff128Svikas int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 29193ebf6f0aSRob Swindell u16 ext, u16 *index, u32 *item_length, 29203ebf6f0aSRob Swindell u32 *data_length) 29213ebf6f0aSRob Swindell { 2922bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_output *output; 2923bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_input *req; 29243ebf6f0aSRob Swindell struct bnxt *bp = netdev_priv(dev); 29253ebf6f0aSRob Swindell int rc; 29263ebf6f0aSRob Swindell 2927bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 2928bbf33d1dSEdwin Peer if (rc) 2929bbf33d1dSEdwin Peer return rc; 2930bbf33d1dSEdwin Peer 2931bbf33d1dSEdwin Peer req->enables = 0; 2932bbf33d1dSEdwin Peer req->dir_idx = 0; 2933bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(type); 2934bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(ordinal); 2935bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(ext); 2936bbf33d1dSEdwin Peer req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 2937bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2938bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 29393ebf6f0aSRob Swindell if (rc == 0) { 29403ebf6f0aSRob Swindell if (index) 29413ebf6f0aSRob Swindell *index = le16_to_cpu(output->dir_idx); 29423ebf6f0aSRob Swindell if (item_length) 29433ebf6f0aSRob Swindell *item_length = le32_to_cpu(output->dir_item_length); 29443ebf6f0aSRob Swindell if (data_length) 29453ebf6f0aSRob Swindell *data_length = le32_to_cpu(output->dir_data_length); 29463ebf6f0aSRob Swindell } 2947bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 29483ebf6f0aSRob Swindell return rc; 29493ebf6f0aSRob Swindell } 29503ebf6f0aSRob Swindell 29513ebf6f0aSRob Swindell static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 29523ebf6f0aSRob Swindell { 29533ebf6f0aSRob Swindell char *retval = NULL; 29543ebf6f0aSRob Swindell char *p; 29553ebf6f0aSRob Swindell char *value; 29563ebf6f0aSRob Swindell int field = 0; 29573ebf6f0aSRob Swindell 29583ebf6f0aSRob Swindell if (datalen < 1) 29593ebf6f0aSRob Swindell return NULL; 29603ebf6f0aSRob Swindell /* null-terminate the log data (removing last '\n'): */ 29613ebf6f0aSRob Swindell data[datalen - 1] = 0; 29623ebf6f0aSRob Swindell for (p = data; *p != 0; p++) { 29633ebf6f0aSRob Swindell field = 0; 29643ebf6f0aSRob Swindell retval = NULL; 29653ebf6f0aSRob Swindell while (*p != 0 && *p != '\n') { 29663ebf6f0aSRob Swindell value = p; 29673ebf6f0aSRob Swindell while (*p != 0 && *p != '\t' && *p != '\n') 29683ebf6f0aSRob Swindell p++; 29693ebf6f0aSRob Swindell if (field == desired_field) 29703ebf6f0aSRob Swindell retval = value; 29713ebf6f0aSRob Swindell if (*p != '\t') 29723ebf6f0aSRob Swindell break; 29733ebf6f0aSRob Swindell *p = 0; 29743ebf6f0aSRob Swindell field++; 29753ebf6f0aSRob Swindell p++; 29763ebf6f0aSRob Swindell } 29773ebf6f0aSRob Swindell if (*p == 0) 29783ebf6f0aSRob Swindell break; 29793ebf6f0aSRob Swindell *p = 0; 29803ebf6f0aSRob Swindell } 29813ebf6f0aSRob Swindell return retval; 29823ebf6f0aSRob Swindell } 29833ebf6f0aSRob Swindell 298463185eb3SVikas Gupta int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 29853ebf6f0aSRob Swindell { 2986a60faa60SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 29873ebf6f0aSRob Swindell u16 index = 0; 2988a60faa60SVasundhara Volam char *pkgver; 2989a60faa60SVasundhara Volam u32 pkglen; 2990a60faa60SVasundhara Volam u8 *pkgbuf; 299163185eb3SVikas Gupta int rc; 29923ebf6f0aSRob Swindell 299363185eb3SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 29943ebf6f0aSRob Swindell BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 299563185eb3SVikas Gupta &index, NULL, &pkglen); 299663185eb3SVikas Gupta if (rc) 299763185eb3SVikas Gupta return rc; 29983ebf6f0aSRob Swindell 2999a60faa60SVasundhara Volam pkgbuf = kzalloc(pkglen, GFP_KERNEL); 3000a60faa60SVasundhara Volam if (!pkgbuf) { 3001a60faa60SVasundhara Volam dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 3002a60faa60SVasundhara Volam pkglen); 300363185eb3SVikas Gupta return -ENOMEM; 3004a60faa60SVasundhara Volam } 30053ebf6f0aSRob Swindell 300663185eb3SVikas Gupta rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 300763185eb3SVikas Gupta if (rc) 3008a60faa60SVasundhara Volam goto err; 3009a60faa60SVasundhara Volam 3010a60faa60SVasundhara Volam pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 3011a60faa60SVasundhara Volam pkglen); 301263185eb3SVikas Gupta if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 301363185eb3SVikas Gupta strscpy(ver, pkgver, size); 301463185eb3SVikas Gupta else 301563185eb3SVikas Gupta rc = -ENOENT; 301663185eb3SVikas Gupta 3017a60faa60SVasundhara Volam err: 3018a60faa60SVasundhara Volam kfree(pkgbuf); 301963185eb3SVikas Gupta 302063185eb3SVikas Gupta return rc; 302163185eb3SVikas Gupta } 302263185eb3SVikas Gupta 302363185eb3SVikas Gupta static void bnxt_get_pkgver(struct net_device *dev) 302463185eb3SVikas Gupta { 302563185eb3SVikas Gupta struct bnxt *bp = netdev_priv(dev); 302663185eb3SVikas Gupta char buf[FW_VER_STR_LEN]; 302763185eb3SVikas Gupta int len; 302863185eb3SVikas Gupta 302963185eb3SVikas Gupta if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 303063185eb3SVikas Gupta len = strlen(bp->fw_ver_str); 303163185eb3SVikas Gupta snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 303263185eb3SVikas Gupta "/pkg %s", buf); 303363185eb3SVikas Gupta } 30343ebf6f0aSRob Swindell } 30353ebf6f0aSRob Swindell 3036c0c050c5SMichael Chan static int bnxt_get_eeprom(struct net_device *dev, 3037c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 3038c0c050c5SMichael Chan u8 *data) 3039c0c050c5SMichael Chan { 3040c0c050c5SMichael Chan u32 index; 3041c0c050c5SMichael Chan u32 offset; 3042c0c050c5SMichael Chan 3043c0c050c5SMichael Chan if (eeprom->offset == 0) /* special offset value to get directory */ 3044c0c050c5SMichael Chan return bnxt_get_nvram_directory(dev, eeprom->len, data); 3045c0c050c5SMichael Chan 3046c0c050c5SMichael Chan index = eeprom->offset >> 24; 3047c0c050c5SMichael Chan offset = eeprom->offset & 0xffffff; 3048c0c050c5SMichael Chan 3049c0c050c5SMichael Chan if (index == 0) { 3050c0c050c5SMichael Chan netdev_err(dev, "unsupported index value: %d\n", index); 3051c0c050c5SMichael Chan return -EINVAL; 3052c0c050c5SMichael Chan } 3053c0c050c5SMichael Chan 3054c0c050c5SMichael Chan return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 3055c0c050c5SMichael Chan } 3056c0c050c5SMichael Chan 3057c0c050c5SMichael Chan static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 3058c0c050c5SMichael Chan { 3059bbf33d1dSEdwin Peer struct hwrm_nvm_erase_dir_entry_input *req; 3060c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3061bbf33d1dSEdwin Peer int rc; 3062c0c050c5SMichael Chan 3063bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 3064bbf33d1dSEdwin Peer if (rc) 3065bbf33d1dSEdwin Peer return rc; 3066bbf33d1dSEdwin Peer 3067bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 3068bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3069c0c050c5SMichael Chan } 3070c0c050c5SMichael Chan 3071c0c050c5SMichael Chan static int bnxt_set_eeprom(struct net_device *dev, 3072c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 3073c0c050c5SMichael Chan u8 *data) 3074c0c050c5SMichael Chan { 3075c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3076c0c050c5SMichael Chan u8 index, dir_op; 3077c0c050c5SMichael Chan u16 type, ext, ordinal, attr; 3078c0c050c5SMichael Chan 3079c0c050c5SMichael Chan if (!BNXT_PF(bp)) { 3080c0c050c5SMichael Chan netdev_err(dev, "NVM write not supported from a virtual function\n"); 3081c0c050c5SMichael Chan return -EINVAL; 3082c0c050c5SMichael Chan } 3083c0c050c5SMichael Chan 3084c0c050c5SMichael Chan type = eeprom->magic >> 16; 3085c0c050c5SMichael Chan 3086c0c050c5SMichael Chan if (type == 0xffff) { /* special value for directory operations */ 3087c0c050c5SMichael Chan index = eeprom->magic & 0xff; 3088c0c050c5SMichael Chan dir_op = eeprom->magic >> 8; 3089c0c050c5SMichael Chan if (index == 0) 3090c0c050c5SMichael Chan return -EINVAL; 3091c0c050c5SMichael Chan switch (dir_op) { 3092c0c050c5SMichael Chan case 0x0e: /* erase */ 3093c0c050c5SMichael Chan if (eeprom->offset != ~eeprom->magic) 3094c0c050c5SMichael Chan return -EINVAL; 3095c0c050c5SMichael Chan return bnxt_erase_nvram_directory(dev, index - 1); 3096c0c050c5SMichael Chan default: 3097c0c050c5SMichael Chan return -EINVAL; 3098c0c050c5SMichael Chan } 3099c0c050c5SMichael Chan } 3100c0c050c5SMichael Chan 3101c0c050c5SMichael Chan /* Create or re-write an NVM item: */ 3102ba425800SJason Yan if (bnxt_dir_type_is_executable(type)) 31035ac67d8bSRob Swindell return -EOPNOTSUPP; 3104c0c050c5SMichael Chan ext = eeprom->magic & 0xffff; 3105c0c050c5SMichael Chan ordinal = eeprom->offset >> 16; 3106c0c050c5SMichael Chan attr = eeprom->offset & 0xffff; 3107c0c050c5SMichael Chan 3108bbf33d1dSEdwin Peer return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 3109c0c050c5SMichael Chan eeprom->len); 3110c0c050c5SMichael Chan } 3111c0c050c5SMichael Chan 311272b34f04SMichael Chan static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 311372b34f04SMichael Chan { 311472b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 311572b34f04SMichael Chan struct ethtool_eee *eee = &bp->eee; 311672b34f04SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 3117a5390690SMichael Chan u32 advertising; 311872b34f04SMichael Chan int rc = 0; 311972b34f04SMichael Chan 3120c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 312175362a3fSMichael Chan return -EOPNOTSUPP; 312272b34f04SMichael Chan 3123b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 312472b34f04SMichael Chan return -EOPNOTSUPP; 312572b34f04SMichael Chan 3126a5390690SMichael Chan mutex_lock(&bp->link_lock); 3127a5390690SMichael Chan advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 312872b34f04SMichael Chan if (!edata->eee_enabled) 312972b34f04SMichael Chan goto eee_ok; 313072b34f04SMichael Chan 313172b34f04SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 313272b34f04SMichael Chan netdev_warn(dev, "EEE requires autoneg\n"); 3133a5390690SMichael Chan rc = -EINVAL; 3134a5390690SMichael Chan goto eee_exit; 313572b34f04SMichael Chan } 313672b34f04SMichael Chan if (edata->tx_lpi_enabled) { 313772b34f04SMichael Chan if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 313872b34f04SMichael Chan edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 313972b34f04SMichael Chan netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 314072b34f04SMichael Chan bp->lpi_tmr_lo, bp->lpi_tmr_hi); 3141a5390690SMichael Chan rc = -EINVAL; 3142a5390690SMichael Chan goto eee_exit; 314372b34f04SMichael Chan } else if (!bp->lpi_tmr_hi) { 314472b34f04SMichael Chan edata->tx_lpi_timer = eee->tx_lpi_timer; 314572b34f04SMichael Chan } 314672b34f04SMichael Chan } 314772b34f04SMichael Chan if (!edata->advertised) { 314872b34f04SMichael Chan edata->advertised = advertising & eee->supported; 314972b34f04SMichael Chan } else if (edata->advertised & ~advertising) { 315072b34f04SMichael Chan netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 315172b34f04SMichael Chan edata->advertised, advertising); 3152a5390690SMichael Chan rc = -EINVAL; 3153a5390690SMichael Chan goto eee_exit; 315472b34f04SMichael Chan } 315572b34f04SMichael Chan 315672b34f04SMichael Chan eee->advertised = edata->advertised; 315772b34f04SMichael Chan eee->tx_lpi_enabled = edata->tx_lpi_enabled; 315872b34f04SMichael Chan eee->tx_lpi_timer = edata->tx_lpi_timer; 315972b34f04SMichael Chan eee_ok: 316072b34f04SMichael Chan eee->eee_enabled = edata->eee_enabled; 316172b34f04SMichael Chan 316272b34f04SMichael Chan if (netif_running(dev)) 316372b34f04SMichael Chan rc = bnxt_hwrm_set_link_setting(bp, false, true); 316472b34f04SMichael Chan 3165a5390690SMichael Chan eee_exit: 3166a5390690SMichael Chan mutex_unlock(&bp->link_lock); 316772b34f04SMichael Chan return rc; 316872b34f04SMichael Chan } 316972b34f04SMichael Chan 317072b34f04SMichael Chan static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 317172b34f04SMichael Chan { 317272b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 317372b34f04SMichael Chan 3174b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 317572b34f04SMichael Chan return -EOPNOTSUPP; 317672b34f04SMichael Chan 317772b34f04SMichael Chan *edata = bp->eee; 317872b34f04SMichael Chan if (!bp->eee.eee_enabled) { 317972b34f04SMichael Chan /* Preserve tx_lpi_timer so that the last value will be used 318072b34f04SMichael Chan * by default when it is re-enabled. 318172b34f04SMichael Chan */ 318272b34f04SMichael Chan edata->advertised = 0; 318372b34f04SMichael Chan edata->tx_lpi_enabled = 0; 318472b34f04SMichael Chan } 318572b34f04SMichael Chan 318672b34f04SMichael Chan if (!bp->eee.eee_active) 318772b34f04SMichael Chan edata->lp_advertised = 0; 318872b34f04SMichael Chan 318972b34f04SMichael Chan return 0; 319072b34f04SMichael Chan } 319172b34f04SMichael Chan 319242ee18feSAjit Khaparde static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 31937ef3d390SVikas Gupta u16 page_number, u8 bank, 31947ef3d390SVikas Gupta u16 start_addr, u16 data_length, 31957ef3d390SVikas Gupta u8 *buf) 319642ee18feSAjit Khaparde { 3197bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_output *output; 3198bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_input *req; 319942ee18feSAjit Khaparde int rc, byte_offset = 0; 320042ee18feSAjit Khaparde 3201bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 3202bbf33d1dSEdwin Peer if (rc) 3203bbf33d1dSEdwin Peer return rc; 3204bbf33d1dSEdwin Peer 3205bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 3206bbf33d1dSEdwin Peer req->i2c_slave_addr = i2c_addr; 3207bbf33d1dSEdwin Peer req->page_number = cpu_to_le16(page_number); 3208bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(bp->pf.port_id); 320942ee18feSAjit Khaparde do { 321042ee18feSAjit Khaparde u16 xfer_size; 321142ee18feSAjit Khaparde 321242ee18feSAjit Khaparde xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 321342ee18feSAjit Khaparde data_length -= xfer_size; 3214bbf33d1dSEdwin Peer req->page_offset = cpu_to_le16(start_addr + byte_offset); 3215bbf33d1dSEdwin Peer req->data_length = xfer_size; 32167ef3d390SVikas Gupta req->enables = 32177ef3d390SVikas Gupta cpu_to_le32((start_addr + byte_offset ? 32187ef3d390SVikas Gupta PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 32197ef3d390SVikas Gupta 0) | 32207ef3d390SVikas Gupta (bank ? 32217ef3d390SVikas Gupta PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : 32227ef3d390SVikas Gupta 0)); 3223bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 322442ee18feSAjit Khaparde if (!rc) 322542ee18feSAjit Khaparde memcpy(buf + byte_offset, output->data, xfer_size); 322642ee18feSAjit Khaparde byte_offset += xfer_size; 322742ee18feSAjit Khaparde } while (!rc && data_length > 0); 3228bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 322942ee18feSAjit Khaparde 323042ee18feSAjit Khaparde return rc; 323142ee18feSAjit Khaparde } 323242ee18feSAjit Khaparde 323342ee18feSAjit Khaparde static int bnxt_get_module_info(struct net_device *dev, 323442ee18feSAjit Khaparde struct ethtool_modinfo *modinfo) 323542ee18feSAjit Khaparde { 32367328a23cSVasundhara Volam u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 323742ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 323842ee18feSAjit Khaparde int rc; 323942ee18feSAjit Khaparde 324042ee18feSAjit Khaparde /* No point in going further if phy status indicates 324142ee18feSAjit Khaparde * module is not inserted or if it is powered down or 324242ee18feSAjit Khaparde * if it is of type 10GBase-T 324342ee18feSAjit Khaparde */ 324442ee18feSAjit Khaparde if (bp->link_info.module_status > 324542ee18feSAjit Khaparde PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 324642ee18feSAjit Khaparde return -EOPNOTSUPP; 324742ee18feSAjit Khaparde 324842ee18feSAjit Khaparde /* This feature is not supported in older firmware versions */ 324942ee18feSAjit Khaparde if (bp->hwrm_spec_code < 0x10202) 325042ee18feSAjit Khaparde return -EOPNOTSUPP; 325142ee18feSAjit Khaparde 32527ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, 32537328a23cSVasundhara Volam SFF_DIAG_SUPPORT_OFFSET + 1, 32547328a23cSVasundhara Volam data); 325542ee18feSAjit Khaparde if (!rc) { 32567328a23cSVasundhara Volam u8 module_id = data[0]; 32577328a23cSVasundhara Volam u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 325842ee18feSAjit Khaparde 325942ee18feSAjit Khaparde switch (module_id) { 326042ee18feSAjit Khaparde case SFF_MODULE_ID_SFP: 326142ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8472; 326242ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 32637328a23cSVasundhara Volam if (!diag_supported) 32647328a23cSVasundhara Volam modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 326542ee18feSAjit Khaparde break; 326642ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP: 326742ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP_PLUS: 326842ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8436; 326942ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 327042ee18feSAjit Khaparde break; 327142ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP28: 327242ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8636; 327342ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 327442ee18feSAjit Khaparde break; 327542ee18feSAjit Khaparde default: 327642ee18feSAjit Khaparde rc = -EOPNOTSUPP; 327742ee18feSAjit Khaparde break; 327842ee18feSAjit Khaparde } 327942ee18feSAjit Khaparde } 328042ee18feSAjit Khaparde return rc; 328142ee18feSAjit Khaparde } 328242ee18feSAjit Khaparde 328342ee18feSAjit Khaparde static int bnxt_get_module_eeprom(struct net_device *dev, 328442ee18feSAjit Khaparde struct ethtool_eeprom *eeprom, 328542ee18feSAjit Khaparde u8 *data) 328642ee18feSAjit Khaparde { 328742ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 328842ee18feSAjit Khaparde u16 start = eeprom->offset, length = eeprom->len; 3289f3ea3119SColin Ian King int rc = 0; 329042ee18feSAjit Khaparde 329142ee18feSAjit Khaparde memset(data, 0, eeprom->len); 329242ee18feSAjit Khaparde 329342ee18feSAjit Khaparde /* Read A0 portion of the EEPROM */ 329442ee18feSAjit Khaparde if (start < ETH_MODULE_SFF_8436_LEN) { 329542ee18feSAjit Khaparde if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 329642ee18feSAjit Khaparde length = ETH_MODULE_SFF_8436_LEN - start; 32977ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 329842ee18feSAjit Khaparde start, length, data); 329942ee18feSAjit Khaparde if (rc) 330042ee18feSAjit Khaparde return rc; 330142ee18feSAjit Khaparde start += length; 330242ee18feSAjit Khaparde data += length; 330342ee18feSAjit Khaparde length = eeprom->len - length; 330442ee18feSAjit Khaparde } 330542ee18feSAjit Khaparde 330642ee18feSAjit Khaparde /* Read A2 portion of the EEPROM */ 330742ee18feSAjit Khaparde if (length) { 330842ee18feSAjit Khaparde start -= ETH_MODULE_SFF_8436_LEN; 33097ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, 3310dea521a2SChristophe JAILLET start, length, data); 331142ee18feSAjit Khaparde } 331242ee18feSAjit Khaparde return rc; 331342ee18feSAjit Khaparde } 331442ee18feSAjit Khaparde 33157ef3d390SVikas Gupta static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) 33167ef3d390SVikas Gupta { 33177ef3d390SVikas Gupta if (bp->link_info.module_status <= 33187ef3d390SVikas Gupta PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 33197ef3d390SVikas Gupta return 0; 33207ef3d390SVikas Gupta 33217ef3d390SVikas Gupta switch (bp->link_info.module_status) { 33227ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: 33237ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); 33247ef3d390SVikas Gupta break; 33257ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: 33267ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); 33277ef3d390SVikas Gupta break; 33287ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: 33297ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault"); 33307ef3d390SVikas Gupta break; 33317ef3d390SVikas Gupta default: 33327ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Unknown error"); 33337ef3d390SVikas Gupta break; 33347ef3d390SVikas Gupta } 33357ef3d390SVikas Gupta return -EINVAL; 33367ef3d390SVikas Gupta } 33377ef3d390SVikas Gupta 33387ef3d390SVikas Gupta static int bnxt_get_module_eeprom_by_page(struct net_device *dev, 33397ef3d390SVikas Gupta const struct ethtool_module_eeprom *page_data, 33407ef3d390SVikas Gupta struct netlink_ext_ack *extack) 33417ef3d390SVikas Gupta { 33427ef3d390SVikas Gupta struct bnxt *bp = netdev_priv(dev); 33437ef3d390SVikas Gupta int rc; 33447ef3d390SVikas Gupta 33457ef3d390SVikas Gupta rc = bnxt_get_module_status(bp, extack); 33467ef3d390SVikas Gupta if (rc) 33477ef3d390SVikas Gupta return rc; 33487ef3d390SVikas Gupta 33497ef3d390SVikas Gupta if (bp->hwrm_spec_code < 0x10202) { 33507ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); 33517ef3d390SVikas Gupta return -EINVAL; 33527ef3d390SVikas Gupta } 33537ef3d390SVikas Gupta 33547ef3d390SVikas Gupta if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { 33557ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); 33567ef3d390SVikas Gupta return -EINVAL; 33577ef3d390SVikas Gupta } 33587ef3d390SVikas Gupta 33597ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, 33607ef3d390SVikas Gupta page_data->page, page_data->bank, 33617ef3d390SVikas Gupta page_data->offset, 33627ef3d390SVikas Gupta page_data->length, 33637ef3d390SVikas Gupta page_data->data); 33647ef3d390SVikas Gupta if (rc) { 33657ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); 33667ef3d390SVikas Gupta return rc; 33677ef3d390SVikas Gupta } 33687ef3d390SVikas Gupta return page_data->length; 33697ef3d390SVikas Gupta } 33707ef3d390SVikas Gupta 3371ae8e98a6SDeepak Khungar static int bnxt_nway_reset(struct net_device *dev) 3372ae8e98a6SDeepak Khungar { 3373ae8e98a6SDeepak Khungar int rc = 0; 3374ae8e98a6SDeepak Khungar 3375ae8e98a6SDeepak Khungar struct bnxt *bp = netdev_priv(dev); 3376ae8e98a6SDeepak Khungar struct bnxt_link_info *link_info = &bp->link_info; 3377ae8e98a6SDeepak Khungar 3378c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 3379ae8e98a6SDeepak Khungar return -EOPNOTSUPP; 3380ae8e98a6SDeepak Khungar 3381ae8e98a6SDeepak Khungar if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 3382ae8e98a6SDeepak Khungar return -EINVAL; 3383ae8e98a6SDeepak Khungar 3384ae8e98a6SDeepak Khungar if (netif_running(dev)) 3385ae8e98a6SDeepak Khungar rc = bnxt_hwrm_set_link_setting(bp, true, false); 3386ae8e98a6SDeepak Khungar 3387ae8e98a6SDeepak Khungar return rc; 3388ae8e98a6SDeepak Khungar } 3389ae8e98a6SDeepak Khungar 33905ad2cbeeSMichael Chan static int bnxt_set_phys_id(struct net_device *dev, 33915ad2cbeeSMichael Chan enum ethtool_phys_id_state state) 33925ad2cbeeSMichael Chan { 3393bbf33d1dSEdwin Peer struct hwrm_port_led_cfg_input *req; 33945ad2cbeeSMichael Chan struct bnxt *bp = netdev_priv(dev); 33955ad2cbeeSMichael Chan struct bnxt_pf_info *pf = &bp->pf; 33965ad2cbeeSMichael Chan struct bnxt_led_cfg *led_cfg; 33975ad2cbeeSMichael Chan u8 led_state; 33985ad2cbeeSMichael Chan __le16 duration; 3399bbf33d1dSEdwin Peer int rc, i; 34005ad2cbeeSMichael Chan 34015ad2cbeeSMichael Chan if (!bp->num_leds || BNXT_VF(bp)) 34025ad2cbeeSMichael Chan return -EOPNOTSUPP; 34035ad2cbeeSMichael Chan 34045ad2cbeeSMichael Chan if (state == ETHTOOL_ID_ACTIVE) { 34055ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 34065ad2cbeeSMichael Chan duration = cpu_to_le16(500); 34075ad2cbeeSMichael Chan } else if (state == ETHTOOL_ID_INACTIVE) { 34085ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 34095ad2cbeeSMichael Chan duration = cpu_to_le16(0); 34105ad2cbeeSMichael Chan } else { 34115ad2cbeeSMichael Chan return -EINVAL; 34125ad2cbeeSMichael Chan } 3413bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 3414bbf33d1dSEdwin Peer if (rc) 3415bbf33d1dSEdwin Peer return rc; 3416bbf33d1dSEdwin Peer 3417bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(pf->port_id); 3418bbf33d1dSEdwin Peer req->num_leds = bp->num_leds; 3419bbf33d1dSEdwin Peer led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 34205ad2cbeeSMichael Chan for (i = 0; i < bp->num_leds; i++, led_cfg++) { 3421bbf33d1dSEdwin Peer req->enables |= BNXT_LED_DFLT_ENABLES(i); 34225ad2cbeeSMichael Chan led_cfg->led_id = bp->leds[i].led_id; 34235ad2cbeeSMichael Chan led_cfg->led_state = led_state; 34245ad2cbeeSMichael Chan led_cfg->led_blink_on = duration; 34255ad2cbeeSMichael Chan led_cfg->led_blink_off = duration; 34265ad2cbeeSMichael Chan led_cfg->led_group_id = bp->leds[i].led_group_id; 34275ad2cbeeSMichael Chan } 3428bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 34295ad2cbeeSMichael Chan } 34305ad2cbeeSMichael Chan 343167fea463SMichael Chan static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 343267fea463SMichael Chan { 3433bbf33d1dSEdwin Peer struct hwrm_selftest_irq_input *req; 3434bbf33d1dSEdwin Peer int rc; 343567fea463SMichael Chan 3436bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 3437bbf33d1dSEdwin Peer if (rc) 3438bbf33d1dSEdwin Peer return rc; 3439bbf33d1dSEdwin Peer 3440bbf33d1dSEdwin Peer req->cmpl_ring = cpu_to_le16(cmpl_ring); 3441bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 344267fea463SMichael Chan } 344367fea463SMichael Chan 344467fea463SMichael Chan static int bnxt_test_irq(struct bnxt *bp) 344567fea463SMichael Chan { 344667fea463SMichael Chan int i; 344767fea463SMichael Chan 344867fea463SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 344967fea463SMichael Chan u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 345067fea463SMichael Chan int rc; 345167fea463SMichael Chan 345267fea463SMichael Chan rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 345367fea463SMichael Chan if (rc) 345467fea463SMichael Chan return rc; 345567fea463SMichael Chan } 345667fea463SMichael Chan return 0; 345767fea463SMichael Chan } 345867fea463SMichael Chan 3459f7dc1ea6SMichael Chan static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 3460f7dc1ea6SMichael Chan { 3461bbf33d1dSEdwin Peer struct hwrm_port_mac_cfg_input *req; 3462bbf33d1dSEdwin Peer int rc; 3463f7dc1ea6SMichael Chan 3464bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 3465bbf33d1dSEdwin Peer if (rc) 3466bbf33d1dSEdwin Peer return rc; 3467f7dc1ea6SMichael Chan 3468bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 3469f7dc1ea6SMichael Chan if (enable) 3470bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 3471f7dc1ea6SMichael Chan else 3472bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 3473bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3474f7dc1ea6SMichael Chan } 3475f7dc1ea6SMichael Chan 347656d37462SVasundhara Volam static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 347756d37462SVasundhara Volam { 3478bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_output *resp; 3479bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_input *req; 348056d37462SVasundhara Volam int rc; 348156d37462SVasundhara Volam 3482bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 3483bbf33d1dSEdwin Peer if (rc) 3484bbf33d1dSEdwin Peer return rc; 3485bbf33d1dSEdwin Peer 3486bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3487bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 348856d37462SVasundhara Volam if (!rc) 348956d37462SVasundhara Volam *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 349056d37462SVasundhara Volam 3491bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 349256d37462SVasundhara Volam return rc; 349356d37462SVasundhara Volam } 349456d37462SVasundhara Volam 349591725d89SMichael Chan static int bnxt_disable_an_for_lpbk(struct bnxt *bp, 349691725d89SMichael Chan struct hwrm_port_phy_cfg_input *req) 349791725d89SMichael Chan { 349891725d89SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 349956d37462SVasundhara Volam u16 fw_advertising; 350091725d89SMichael Chan u16 fw_speed; 350191725d89SMichael Chan int rc; 350291725d89SMichael Chan 35038a60efd1SMichael Chan if (!link_info->autoneg || 3504b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 350591725d89SMichael Chan return 0; 350691725d89SMichael Chan 350756d37462SVasundhara Volam rc = bnxt_query_force_speeds(bp, &fw_advertising); 350856d37462SVasundhara Volam if (rc) 350956d37462SVasundhara Volam return rc; 351056d37462SVasundhara Volam 351191725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 35120f5a4841SEdwin Peer if (BNXT_LINK_IS_UP(bp)) 351391725d89SMichael Chan fw_speed = bp->link_info.link_speed; 351491725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 351591725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 351691725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 351791725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 351891725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 351991725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 352091725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 352191725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 352291725d89SMichael Chan 352391725d89SMichael Chan req->force_link_speed = cpu_to_le16(fw_speed); 352491725d89SMichael Chan req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 352591725d89SMichael Chan PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 3526bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 352791725d89SMichael Chan req->flags = 0; 352891725d89SMichael Chan req->force_link_speed = cpu_to_le16(0); 352991725d89SMichael Chan return rc; 353091725d89SMichael Chan } 353191725d89SMichael Chan 353255fd0cf3SMichael Chan static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 353391725d89SMichael Chan { 3534bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 3535bbf33d1dSEdwin Peer int rc; 353691725d89SMichael Chan 3537bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 3538bbf33d1dSEdwin Peer if (rc) 3539bbf33d1dSEdwin Peer return rc; 3540bbf33d1dSEdwin Peer 3541bbf33d1dSEdwin Peer /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 3542bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 354391725d89SMichael Chan 354491725d89SMichael Chan if (enable) { 3545bbf33d1dSEdwin Peer bnxt_disable_an_for_lpbk(bp, req); 354655fd0cf3SMichael Chan if (ext) 3547bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 354855fd0cf3SMichael Chan else 3549bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 355091725d89SMichael Chan } else { 3551bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 355291725d89SMichael Chan } 3553bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 3554bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3555bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3556bbf33d1dSEdwin Peer return rc; 355791725d89SMichael Chan } 355891725d89SMichael Chan 3559e44758b7SMichael Chan static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3560f7dc1ea6SMichael Chan u32 raw_cons, int pkt_size) 3561f7dc1ea6SMichael Chan { 3562e44758b7SMichael Chan struct bnxt_napi *bnapi = cpr->bnapi; 3563e44758b7SMichael Chan struct bnxt_rx_ring_info *rxr; 3564f7dc1ea6SMichael Chan struct bnxt_sw_rx_bd *rx_buf; 3565f7dc1ea6SMichael Chan struct rx_cmp *rxcmp; 3566f7dc1ea6SMichael Chan u16 cp_cons, cons; 3567f7dc1ea6SMichael Chan u8 *data; 3568f7dc1ea6SMichael Chan u32 len; 3569f7dc1ea6SMichael Chan int i; 3570f7dc1ea6SMichael Chan 3571e44758b7SMichael Chan rxr = bnapi->rx_ring; 3572f7dc1ea6SMichael Chan cp_cons = RING_CMP(raw_cons); 3573f7dc1ea6SMichael Chan rxcmp = (struct rx_cmp *) 3574f7dc1ea6SMichael Chan &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 3575f7dc1ea6SMichael Chan cons = rxcmp->rx_cmp_opaque; 3576f7dc1ea6SMichael Chan rx_buf = &rxr->rx_buf_ring[cons]; 3577f7dc1ea6SMichael Chan data = rx_buf->data_ptr; 3578f7dc1ea6SMichael Chan len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 3579f7dc1ea6SMichael Chan if (len != pkt_size) 3580f7dc1ea6SMichael Chan return -EIO; 3581f7dc1ea6SMichael Chan i = ETH_ALEN; 3582f7dc1ea6SMichael Chan if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 3583f7dc1ea6SMichael Chan return -EIO; 3584f7dc1ea6SMichael Chan i += ETH_ALEN; 3585f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) { 3586f7dc1ea6SMichael Chan if (data[i] != (u8)(i & 0xff)) 3587f7dc1ea6SMichael Chan return -EIO; 3588f7dc1ea6SMichael Chan } 3589f7dc1ea6SMichael Chan return 0; 3590f7dc1ea6SMichael Chan } 3591f7dc1ea6SMichael Chan 3592e44758b7SMichael Chan static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3593e44758b7SMichael Chan int pkt_size) 3594f7dc1ea6SMichael Chan { 3595f7dc1ea6SMichael Chan struct tx_cmp *txcmp; 3596f7dc1ea6SMichael Chan int rc = -EIO; 3597f7dc1ea6SMichael Chan u32 raw_cons; 3598f7dc1ea6SMichael Chan u32 cons; 3599f7dc1ea6SMichael Chan int i; 3600f7dc1ea6SMichael Chan 3601f7dc1ea6SMichael Chan raw_cons = cpr->cp_raw_cons; 3602f7dc1ea6SMichael Chan for (i = 0; i < 200; i++) { 3603f7dc1ea6SMichael Chan cons = RING_CMP(raw_cons); 3604f7dc1ea6SMichael Chan txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 3605f7dc1ea6SMichael Chan 3606f7dc1ea6SMichael Chan if (!TX_CMP_VALID(txcmp, raw_cons)) { 3607f7dc1ea6SMichael Chan udelay(5); 3608f7dc1ea6SMichael Chan continue; 3609f7dc1ea6SMichael Chan } 3610f7dc1ea6SMichael Chan 3611f7dc1ea6SMichael Chan /* The valid test of the entry must be done first before 3612f7dc1ea6SMichael Chan * reading any further. 3613f7dc1ea6SMichael Chan */ 3614f7dc1ea6SMichael Chan dma_rmb(); 3615f7dc1ea6SMichael Chan if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 3616e44758b7SMichael Chan rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 3617f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3618f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3619f7dc1ea6SMichael Chan break; 3620f7dc1ea6SMichael Chan } 3621f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3622f7dc1ea6SMichael Chan } 3623f7dc1ea6SMichael Chan cpr->cp_raw_cons = raw_cons; 3624f7dc1ea6SMichael Chan return rc; 3625f7dc1ea6SMichael Chan } 3626f7dc1ea6SMichael Chan 3627f7dc1ea6SMichael Chan static int bnxt_run_loopback(struct bnxt *bp) 3628f7dc1ea6SMichael Chan { 3629f7dc1ea6SMichael Chan struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 363084404d5fSMichael Chan struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 3631e44758b7SMichael Chan struct bnxt_cp_ring_info *cpr; 3632f7dc1ea6SMichael Chan int pkt_size, i = 0; 3633f7dc1ea6SMichael Chan struct sk_buff *skb; 3634f7dc1ea6SMichael Chan dma_addr_t map; 3635f7dc1ea6SMichael Chan u8 *data; 3636f7dc1ea6SMichael Chan int rc; 3637f7dc1ea6SMichael Chan 363884404d5fSMichael Chan cpr = &rxr->bnapi->cp_ring; 363984404d5fSMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 364084404d5fSMichael Chan cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 3641f7dc1ea6SMichael Chan pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 3642f7dc1ea6SMichael Chan skb = netdev_alloc_skb(bp->dev, pkt_size); 3643f7dc1ea6SMichael Chan if (!skb) 3644f7dc1ea6SMichael Chan return -ENOMEM; 3645f7dc1ea6SMichael Chan data = skb_put(skb, pkt_size); 3646cfcab3b3SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3647f7dc1ea6SMichael Chan i += ETH_ALEN; 3648f7dc1ea6SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3649f7dc1ea6SMichael Chan i += ETH_ALEN; 3650f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) 3651f7dc1ea6SMichael Chan data[i] = (u8)(i & 0xff); 3652f7dc1ea6SMichael Chan 3653f7dc1ea6SMichael Chan map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 3654df70303dSChristophe JAILLET DMA_TO_DEVICE); 3655f7dc1ea6SMichael Chan if (dma_mapping_error(&bp->pdev->dev, map)) { 3656f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3657f7dc1ea6SMichael Chan return -EIO; 3658f7dc1ea6SMichael Chan } 3659a7559bc8SAndy Gospodarek bnxt_xmit_bd(bp, txr, map, pkt_size, NULL); 3660f7dc1ea6SMichael Chan 3661f7dc1ea6SMichael Chan /* Sync BD data before updating doorbell */ 3662f7dc1ea6SMichael Chan wmb(); 3663f7dc1ea6SMichael Chan 3664697197e5SMichael Chan bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 3665e44758b7SMichael Chan rc = bnxt_poll_loopback(bp, cpr, pkt_size); 3666f7dc1ea6SMichael Chan 3667df70303dSChristophe JAILLET dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 3668f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3669f7dc1ea6SMichael Chan return rc; 3670f7dc1ea6SMichael Chan } 3671f7dc1ea6SMichael Chan 3672eb513658SMichael Chan static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 3673eb513658SMichael Chan { 3674bbf33d1dSEdwin Peer struct hwrm_selftest_exec_output *resp; 3675bbf33d1dSEdwin Peer struct hwrm_selftest_exec_input *req; 3676eb513658SMichael Chan int rc; 3677eb513658SMichael Chan 3678bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 3679bbf33d1dSEdwin Peer if (rc) 3680bbf33d1dSEdwin Peer return rc; 3681bbf33d1dSEdwin Peer 3682bbf33d1dSEdwin Peer hwrm_req_timeout(bp, req, bp->test_info->timeout); 3683bbf33d1dSEdwin Peer req->flags = test_mask; 3684bbf33d1dSEdwin Peer 3685bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3686bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3687eb513658SMichael Chan *test_results = resp->test_success; 3688bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3689eb513658SMichael Chan return rc; 3690eb513658SMichael Chan } 3691eb513658SMichael Chan 369255fd0cf3SMichael Chan #define BNXT_DRV_TESTS 4 3693f7dc1ea6SMichael Chan #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 369491725d89SMichael Chan #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 369555fd0cf3SMichael Chan #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 369655fd0cf3SMichael Chan #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 3697eb513658SMichael Chan 3698eb513658SMichael Chan static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 3699eb513658SMichael Chan u64 *buf) 3700eb513658SMichael Chan { 3701eb513658SMichael Chan struct bnxt *bp = netdev_priv(dev); 370255fd0cf3SMichael Chan bool do_ext_lpbk = false; 3703eb513658SMichael Chan bool offline = false; 3704eb513658SMichael Chan u8 test_results = 0; 3705eb513658SMichael Chan u8 test_mask = 0; 3706d27e2ca1SMichael Chan int rc = 0, i; 3707eb513658SMichael Chan 37086896cb35SVasundhara Volam if (!bp->num_tests || !BNXT_PF(bp)) 3709eb513658SMichael Chan return; 3710eb513658SMichael Chan memset(buf, 0, sizeof(u64) * bp->num_tests); 3711eb513658SMichael Chan if (!netif_running(dev)) { 3712eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3713eb513658SMichael Chan return; 3714eb513658SMichael Chan } 3715eb513658SMichael Chan 371655fd0cf3SMichael Chan if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 3717b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 371855fd0cf3SMichael Chan do_ext_lpbk = true; 371955fd0cf3SMichael Chan 3720eb513658SMichael Chan if (etest->flags & ETH_TEST_FL_OFFLINE) { 37216896cb35SVasundhara Volam if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 3722eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 37236896cb35SVasundhara Volam netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 3724eb513658SMichael Chan return; 3725eb513658SMichael Chan } 3726eb513658SMichael Chan offline = true; 3727eb513658SMichael Chan } 3728eb513658SMichael Chan 3729eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3730eb513658SMichael Chan u8 bit_val = 1 << i; 3731eb513658SMichael Chan 3732eb513658SMichael Chan if (!(bp->test_info->offline_mask & bit_val)) 3733eb513658SMichael Chan test_mask |= bit_val; 3734eb513658SMichael Chan else if (offline) 3735eb513658SMichael Chan test_mask |= bit_val; 3736eb513658SMichael Chan } 3737eb513658SMichael Chan if (!offline) { 3738eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3739eb513658SMichael Chan } else { 37406758f937SMichael Chan bnxt_ulp_stop(bp); 37416758f937SMichael Chan rc = bnxt_close_nic(bp, true, false); 37426758f937SMichael Chan if (rc) { 374383714dc3SKalesh AP etest->flags |= ETH_TEST_FL_FAILED; 37446758f937SMichael Chan bnxt_ulp_start(bp, rc); 3745eb513658SMichael Chan return; 37466758f937SMichael Chan } 3747eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3748f7dc1ea6SMichael Chan 3749f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 1; 3750f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, true); 3751f7dc1ea6SMichael Chan msleep(250); 3752f7dc1ea6SMichael Chan rc = bnxt_half_open_nic(bp); 3753f7dc1ea6SMichael Chan if (rc) { 3754f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 3755f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 37566758f937SMichael Chan bnxt_ulp_start(bp, rc); 3757f7dc1ea6SMichael Chan return; 3758f7dc1ea6SMichael Chan } 3759f7dc1ea6SMichael Chan if (bnxt_run_loopback(bp)) 3760f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3761f7dc1ea6SMichael Chan else 3762f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 0; 3763f7dc1ea6SMichael Chan 3764f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 376555fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, false); 376691725d89SMichael Chan msleep(1000); 376791725d89SMichael Chan if (bnxt_run_loopback(bp)) { 376891725d89SMichael Chan buf[BNXT_PHYLPBK_TEST_IDX] = 1; 376991725d89SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 377091725d89SMichael Chan } 377155fd0cf3SMichael Chan if (do_ext_lpbk) { 377255fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 377355fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, true); 377455fd0cf3SMichael Chan msleep(1000); 377555fd0cf3SMichael Chan if (bnxt_run_loopback(bp)) { 377655fd0cf3SMichael Chan buf[BNXT_EXTLPBK_TEST_IDX] = 1; 377755fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 377855fd0cf3SMichael Chan } 377955fd0cf3SMichael Chan } 378055fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, false, false); 378191725d89SMichael Chan bnxt_half_close_nic(bp); 37826758f937SMichael Chan rc = bnxt_open_nic(bp, true, true); 37836758f937SMichael Chan bnxt_ulp_start(bp, rc); 3784eb513658SMichael Chan } 3785d27e2ca1SMichael Chan if (rc || bnxt_test_irq(bp)) { 378667fea463SMichael Chan buf[BNXT_IRQ_TEST_IDX] = 1; 378767fea463SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 378867fea463SMichael Chan } 3789eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3790eb513658SMichael Chan u8 bit_val = 1 << i; 3791eb513658SMichael Chan 3792eb513658SMichael Chan if ((test_mask & bit_val) && !(test_results & bit_val)) { 3793eb513658SMichael Chan buf[i] = 1; 3794eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3795eb513658SMichael Chan } 3796eb513658SMichael Chan } 3797eb513658SMichael Chan } 3798eb513658SMichael Chan 379949f7972fSVasundhara Volam static int bnxt_reset(struct net_device *dev, u32 *flags) 380049f7972fSVasundhara Volam { 380149f7972fSVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38028cec0940SEdwin Peer bool reload = false; 38037a13240eSEdwin Peer u32 req = *flags; 38047a13240eSEdwin Peer 38057a13240eSEdwin Peer if (!req) 38067a13240eSEdwin Peer return -EINVAL; 380749f7972fSVasundhara Volam 380849f7972fSVasundhara Volam if (!BNXT_PF(bp)) { 380949f7972fSVasundhara Volam netdev_err(dev, "Reset is not supported from a VF\n"); 381049f7972fSVasundhara Volam return -EOPNOTSUPP; 381149f7972fSVasundhara Volam } 381249f7972fSVasundhara Volam 38130a3f4e4fSVasundhara Volam if (pci_vfs_assigned(bp->pdev) && 38140a3f4e4fSVasundhara Volam !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 381549f7972fSVasundhara Volam netdev_err(dev, 381649f7972fSVasundhara Volam "Reset not allowed when VFs are assigned to VMs\n"); 381749f7972fSVasundhara Volam return -EBUSY; 381849f7972fSVasundhara Volam } 381949f7972fSVasundhara Volam 38207a13240eSEdwin Peer if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 382149f7972fSVasundhara Volam /* This feature is not supported in older firmware versions */ 38227a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 38237a13240eSEdwin Peer if (!bnxt_firmware_reset_chip(dev)) { 38247a13240eSEdwin Peer netdev_info(dev, "Firmware reset request successful.\n"); 38250a3f4e4fSVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 38268cec0940SEdwin Peer reload = true; 38277a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_CHIP; 38282373d8d6SScott Branden } 38297a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_CHIP) { 38307a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 38317a13240eSEdwin Peer } 38327a13240eSEdwin Peer } 38337a13240eSEdwin Peer 38347a13240eSEdwin Peer if (req & BNXT_FW_RESET_AP) { 38356502ad59SScott Branden /* This feature is not supported in older firmware versions */ 38367a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 38377a13240eSEdwin Peer if (!bnxt_firmware_reset_ap(dev)) { 38387a13240eSEdwin Peer netdev_info(dev, "Reset application processor successful.\n"); 38398cec0940SEdwin Peer reload = true; 38407a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_AP; 38412373d8d6SScott Branden } 38427a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_AP) { 38437a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 38447a13240eSEdwin Peer } 384549f7972fSVasundhara Volam } 384649f7972fSVasundhara Volam 38478cec0940SEdwin Peer if (reload) 38488cec0940SEdwin Peer netdev_info(dev, "Reload driver to complete reset\n"); 38498cec0940SEdwin Peer 38507a13240eSEdwin Peer return 0; 385149f7972fSVasundhara Volam } 385249f7972fSVasundhara Volam 38530b0eacf3SVasundhara Volam static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 38540b0eacf3SVasundhara Volam { 38550b0eacf3SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38560b0eacf3SVasundhara Volam 38570b0eacf3SVasundhara Volam if (dump->flag > BNXT_DUMP_CRASH) { 38580b0eacf3SVasundhara Volam netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 38590b0eacf3SVasundhara Volam return -EINVAL; 38600b0eacf3SVasundhara Volam } 38610b0eacf3SVasundhara Volam 38620b0eacf3SVasundhara Volam if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 38630b0eacf3SVasundhara Volam netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 38640b0eacf3SVasundhara Volam return -EOPNOTSUPP; 38650b0eacf3SVasundhara Volam } 38660b0eacf3SVasundhara Volam 38670b0eacf3SVasundhara Volam bp->dump_flag = dump->flag; 38680b0eacf3SVasundhara Volam return 0; 38690b0eacf3SVasundhara Volam } 38700b0eacf3SVasundhara Volam 38716c5657d0SVasundhara Volam static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 38726c5657d0SVasundhara Volam { 38736c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38746c5657d0SVasundhara Volam 38756c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 38766c5657d0SVasundhara Volam return -EOPNOTSUPP; 38776c5657d0SVasundhara Volam 38786c5657d0SVasundhara Volam dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 38796c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_min_8b << 16 | 38806c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_bld_8b << 8 | 38816c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_rsvd_8b; 38826c5657d0SVasundhara Volam 38830b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 38849a575c8cSEdwin Peer dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 38850b0eacf3SVasundhara Volam return 0; 38866c5657d0SVasundhara Volam } 38876c5657d0SVasundhara Volam 38886c5657d0SVasundhara Volam static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 38896c5657d0SVasundhara Volam void *buf) 38906c5657d0SVasundhara Volam { 38916c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38926c5657d0SVasundhara Volam 38936c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 38946c5657d0SVasundhara Volam return -EOPNOTSUPP; 38956c5657d0SVasundhara Volam 38966c5657d0SVasundhara Volam memset(buf, 0, dump->len); 38976c5657d0SVasundhara Volam 38980b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 38999a575c8cSEdwin Peer return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 39000b0eacf3SVasundhara Volam } 39010b0eacf3SVasundhara Volam 3902118612d5SMichael Chan static int bnxt_get_ts_info(struct net_device *dev, 3903118612d5SMichael Chan struct ethtool_ts_info *info) 3904118612d5SMichael Chan { 3905118612d5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3906118612d5SMichael Chan struct bnxt_ptp_cfg *ptp; 3907118612d5SMichael Chan 3908118612d5SMichael Chan ptp = bp->ptp_cfg; 3909118612d5SMichael Chan info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 3910118612d5SMichael Chan SOF_TIMESTAMPING_RX_SOFTWARE | 3911118612d5SMichael Chan SOF_TIMESTAMPING_SOFTWARE; 3912118612d5SMichael Chan 3913118612d5SMichael Chan info->phc_index = -1; 3914118612d5SMichael Chan if (!ptp) 3915118612d5SMichael Chan return 0; 3916118612d5SMichael Chan 3917118612d5SMichael Chan info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 3918118612d5SMichael Chan SOF_TIMESTAMPING_RX_HARDWARE | 3919118612d5SMichael Chan SOF_TIMESTAMPING_RAW_HARDWARE; 3920118612d5SMichael Chan if (ptp->ptp_clock) 3921118612d5SMichael Chan info->phc_index = ptp_clock_index(ptp->ptp_clock); 3922118612d5SMichael Chan 3923118612d5SMichael Chan info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 3924118612d5SMichael Chan 3925118612d5SMichael Chan info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 3926118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 3927118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 392866ed81dcSPavan Chebbi 392966ed81dcSPavan Chebbi if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) 393066ed81dcSPavan Chebbi info->rx_filters |= (1 << HWTSTAMP_FILTER_ALL); 3931118612d5SMichael Chan return 0; 3932118612d5SMichael Chan } 3933118612d5SMichael Chan 3934eb513658SMichael Chan void bnxt_ethtool_init(struct bnxt *bp) 3935eb513658SMichael Chan { 3936bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_output *resp; 3937bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_input *req; 3938eb513658SMichael Chan struct bnxt_test_info *test_info; 3939431aa1ebSMichael Chan struct net_device *dev = bp->dev; 3940eb513658SMichael Chan int i, rc; 3941eb513658SMichael Chan 3942691aa620SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 3943a60faa60SVasundhara Volam bnxt_get_pkgver(dev); 3944431aa1ebSMichael Chan 3945ba642ab7SMichael Chan bp->num_tests = 0; 39466896cb35SVasundhara Volam if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 3947eb513658SMichael Chan return; 3948eb513658SMichael Chan 3949bbf33d1dSEdwin Peer test_info = bp->test_info; 3950bbf33d1dSEdwin Peer if (!test_info) { 3951bbf33d1dSEdwin Peer test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 3952bbf33d1dSEdwin Peer if (!test_info) 3953bbf33d1dSEdwin Peer return; 3954bbf33d1dSEdwin Peer bp->test_info = test_info; 3955bbf33d1dSEdwin Peer } 3956bbf33d1dSEdwin Peer 3957bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 3958bbf33d1dSEdwin Peer return; 3959bbf33d1dSEdwin Peer 3960bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3961bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 3962eb513658SMichael Chan if (rc) 3963eb513658SMichael Chan goto ethtool_init_exit; 3964eb513658SMichael Chan 3965eb513658SMichael Chan bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 3966eb513658SMichael Chan if (bp->num_tests > BNXT_MAX_TEST) 3967eb513658SMichael Chan bp->num_tests = BNXT_MAX_TEST; 3968eb513658SMichael Chan 3969eb513658SMichael Chan test_info->offline_mask = resp->offline_tests; 3970eb513658SMichael Chan test_info->timeout = le16_to_cpu(resp->test_timeout); 3971eb513658SMichael Chan if (!test_info->timeout) 3972eb513658SMichael Chan test_info->timeout = HWRM_CMD_TIMEOUT; 3973eb513658SMichael Chan for (i = 0; i < bp->num_tests; i++) { 3974eb513658SMichael Chan char *str = test_info->string[i]; 3975d3e599c0SKees Cook char *fw_str = resp->test_name[i]; 3976eb513658SMichael Chan 3977f7dc1ea6SMichael Chan if (i == BNXT_MACLPBK_TEST_IDX) { 3978f7dc1ea6SMichael Chan strcpy(str, "Mac loopback test (offline)"); 397991725d89SMichael Chan } else if (i == BNXT_PHYLPBK_TEST_IDX) { 398091725d89SMichael Chan strcpy(str, "Phy loopback test (offline)"); 398155fd0cf3SMichael Chan } else if (i == BNXT_EXTLPBK_TEST_IDX) { 398255fd0cf3SMichael Chan strcpy(str, "Ext loopback test (offline)"); 398367fea463SMichael Chan } else if (i == BNXT_IRQ_TEST_IDX) { 398467fea463SMichael Chan strcpy(str, "Interrupt_test (offline)"); 3985f7dc1ea6SMichael Chan } else { 3986d3e599c0SKees Cook snprintf(str, ETH_GSTRING_LEN, "%s test (%s)", 3987d3e599c0SKees Cook fw_str, test_info->offline_mask & (1 << i) ? 3988d3e599c0SKees Cook "offline" : "online"); 3989eb513658SMichael Chan } 3990f7dc1ea6SMichael Chan } 3991eb513658SMichael Chan 3992eb513658SMichael Chan ethtool_init_exit: 3993bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3994eb513658SMichael Chan } 3995eb513658SMichael Chan 3996782bc00aSJakub Kicinski static void bnxt_get_eth_phy_stats(struct net_device *dev, 3997782bc00aSJakub Kicinski struct ethtool_eth_phy_stats *phy_stats) 3998782bc00aSJakub Kicinski { 3999782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4000782bc00aSJakub Kicinski u64 *rx; 4001782bc00aSJakub Kicinski 4002782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 4003782bc00aSJakub Kicinski return; 4004782bc00aSJakub Kicinski 4005782bc00aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 4006782bc00aSJakub Kicinski phy_stats->SymbolErrorDuringCarrier = 4007782bc00aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 4008782bc00aSJakub Kicinski } 4009782bc00aSJakub Kicinski 4010782bc00aSJakub Kicinski static void bnxt_get_eth_mac_stats(struct net_device *dev, 4011782bc00aSJakub Kicinski struct ethtool_eth_mac_stats *mac_stats) 4012782bc00aSJakub Kicinski { 4013782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4014782bc00aSJakub Kicinski u64 *rx, *tx; 4015782bc00aSJakub Kicinski 4016782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4017782bc00aSJakub Kicinski return; 4018782bc00aSJakub Kicinski 4019782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4020782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 4021782bc00aSJakub Kicinski 4022782bc00aSJakub Kicinski mac_stats->FramesReceivedOK = 4023782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 4024782bc00aSJakub Kicinski mac_stats->FramesTransmittedOK = 4025782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 402637434782SJakub Kicinski mac_stats->FrameCheckSequenceErrors = 402737434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 402837434782SJakub Kicinski mac_stats->AlignmentErrors = 402937434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 403037434782SJakub Kicinski mac_stats->OutOfRangeLengthField = 403137434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 4032782bc00aSJakub Kicinski } 4033782bc00aSJakub Kicinski 4034782bc00aSJakub Kicinski static void bnxt_get_eth_ctrl_stats(struct net_device *dev, 4035782bc00aSJakub Kicinski struct ethtool_eth_ctrl_stats *ctrl_stats) 4036782bc00aSJakub Kicinski { 4037782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4038782bc00aSJakub Kicinski u64 *rx; 4039782bc00aSJakub Kicinski 4040782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4041782bc00aSJakub Kicinski return; 4042782bc00aSJakub Kicinski 4043782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4044782bc00aSJakub Kicinski ctrl_stats->MACControlFramesReceived = 4045782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 4046782bc00aSJakub Kicinski } 4047782bc00aSJakub Kicinski 4048782bc00aSJakub Kicinski static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 4049782bc00aSJakub Kicinski { 0, 64 }, 4050782bc00aSJakub Kicinski { 65, 127 }, 4051782bc00aSJakub Kicinski { 128, 255 }, 4052782bc00aSJakub Kicinski { 256, 511 }, 4053782bc00aSJakub Kicinski { 512, 1023 }, 4054782bc00aSJakub Kicinski { 1024, 1518 }, 4055782bc00aSJakub Kicinski { 1519, 2047 }, 4056782bc00aSJakub Kicinski { 2048, 4095 }, 4057782bc00aSJakub Kicinski { 4096, 9216 }, 4058782bc00aSJakub Kicinski { 9217, 16383 }, 4059782bc00aSJakub Kicinski {} 4060782bc00aSJakub Kicinski }; 4061782bc00aSJakub Kicinski 4062782bc00aSJakub Kicinski static void bnxt_get_rmon_stats(struct net_device *dev, 4063782bc00aSJakub Kicinski struct ethtool_rmon_stats *rmon_stats, 4064782bc00aSJakub Kicinski const struct ethtool_rmon_hist_range **ranges) 4065782bc00aSJakub Kicinski { 4066782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4067782bc00aSJakub Kicinski u64 *rx, *tx; 4068782bc00aSJakub Kicinski 4069782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4070782bc00aSJakub Kicinski return; 4071782bc00aSJakub Kicinski 4072782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4073782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 4074782bc00aSJakub Kicinski 4075782bc00aSJakub Kicinski rmon_stats->jabbers = 4076782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 4077782bc00aSJakub Kicinski rmon_stats->oversize_pkts = 4078782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 4079782bc00aSJakub Kicinski rmon_stats->undersize_pkts = 4080782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 4081782bc00aSJakub Kicinski 4082782bc00aSJakub Kicinski rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 4083782bc00aSJakub Kicinski rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 4084782bc00aSJakub Kicinski rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 4085782bc00aSJakub Kicinski rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 4086782bc00aSJakub Kicinski rmon_stats->hist[4] = 4087782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 4088782bc00aSJakub Kicinski rmon_stats->hist[5] = 4089782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 4090782bc00aSJakub Kicinski rmon_stats->hist[6] = 4091782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 4092782bc00aSJakub Kicinski rmon_stats->hist[7] = 4093782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 4094782bc00aSJakub Kicinski rmon_stats->hist[8] = 4095782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 4096782bc00aSJakub Kicinski rmon_stats->hist[9] = 4097782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 4098782bc00aSJakub Kicinski 4099782bc00aSJakub Kicinski rmon_stats->hist_tx[0] = 4100782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 4101782bc00aSJakub Kicinski rmon_stats->hist_tx[1] = 4102782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 4103782bc00aSJakub Kicinski rmon_stats->hist_tx[2] = 4104782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 4105782bc00aSJakub Kicinski rmon_stats->hist_tx[3] = 4106782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 4107782bc00aSJakub Kicinski rmon_stats->hist_tx[4] = 4108782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 4109782bc00aSJakub Kicinski rmon_stats->hist_tx[5] = 4110782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 4111782bc00aSJakub Kicinski rmon_stats->hist_tx[6] = 4112782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 4113782bc00aSJakub Kicinski rmon_stats->hist_tx[7] = 4114782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 4115782bc00aSJakub Kicinski rmon_stats->hist_tx[8] = 4116782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 4117782bc00aSJakub Kicinski rmon_stats->hist_tx[9] = 4118782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 4119782bc00aSJakub Kicinski 4120782bc00aSJakub Kicinski *ranges = bnxt_rmon_ranges; 4121782bc00aSJakub Kicinski } 4122782bc00aSJakub Kicinski 41239a0f830fSJakub Kicinski static void bnxt_get_link_ext_stats(struct net_device *dev, 41249a0f830fSJakub Kicinski struct ethtool_link_ext_stats *stats) 41259a0f830fSJakub Kicinski { 41269a0f830fSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 41279a0f830fSJakub Kicinski u64 *rx; 41289a0f830fSJakub Kicinski 41299a0f830fSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 41309a0f830fSJakub Kicinski return; 41319a0f830fSJakub Kicinski 41329a0f830fSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 41339a0f830fSJakub Kicinski stats->link_down_events = 41349a0f830fSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(link_down_events)); 41359a0f830fSJakub Kicinski } 41369a0f830fSJakub Kicinski 4137eb513658SMichael Chan void bnxt_ethtool_free(struct bnxt *bp) 4138eb513658SMichael Chan { 4139eb513658SMichael Chan kfree(bp->test_info); 4140eb513658SMichael Chan bp->test_info = NULL; 4141eb513658SMichael Chan } 4142eb513658SMichael Chan 4143c0c050c5SMichael Chan const struct ethtool_ops bnxt_ethtool_ops = { 4144f704d243SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 4145f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES | 4146f704d243SJakub Kicinski ETHTOOL_COALESCE_USECS_IRQ | 4147f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 4148f704d243SJakub Kicinski ETHTOOL_COALESCE_STATS_BLOCK_USECS | 41493fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 41503fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_CQE, 415100c04a92SMichael Chan .get_link_ksettings = bnxt_get_link_ksettings, 415200c04a92SMichael Chan .set_link_ksettings = bnxt_set_link_ksettings, 4153c9ca5c3aSJakub Kicinski .get_fec_stats = bnxt_get_fec_stats, 41548b277589SMichael Chan .get_fecparam = bnxt_get_fecparam, 4155ccd6a9dcSMichael Chan .set_fecparam = bnxt_set_fecparam, 4156423cffcfSJakub Kicinski .get_pause_stats = bnxt_get_pause_stats, 4157c0c050c5SMichael Chan .get_pauseparam = bnxt_get_pauseparam, 4158c0c050c5SMichael Chan .set_pauseparam = bnxt_set_pauseparam, 4159c0c050c5SMichael Chan .get_drvinfo = bnxt_get_drvinfo, 4160b5d600b0SVasundhara Volam .get_regs_len = bnxt_get_regs_len, 4161b5d600b0SVasundhara Volam .get_regs = bnxt_get_regs, 41628e202366SMichael Chan .get_wol = bnxt_get_wol, 41635282db6cSMichael Chan .set_wol = bnxt_set_wol, 4164c0c050c5SMichael Chan .get_coalesce = bnxt_get_coalesce, 4165c0c050c5SMichael Chan .set_coalesce = bnxt_set_coalesce, 4166c0c050c5SMichael Chan .get_msglevel = bnxt_get_msglevel, 4167c0c050c5SMichael Chan .set_msglevel = bnxt_set_msglevel, 4168c0c050c5SMichael Chan .get_sset_count = bnxt_get_sset_count, 4169c0c050c5SMichael Chan .get_strings = bnxt_get_strings, 4170c0c050c5SMichael Chan .get_ethtool_stats = bnxt_get_ethtool_stats, 4171c0c050c5SMichael Chan .set_ringparam = bnxt_set_ringparam, 4172c0c050c5SMichael Chan .get_ringparam = bnxt_get_ringparam, 4173c0c050c5SMichael Chan .get_channels = bnxt_get_channels, 4174c0c050c5SMichael Chan .set_channels = bnxt_set_channels, 4175c0c050c5SMichael Chan .get_rxnfc = bnxt_get_rxnfc, 4176a011952aSMichael Chan .set_rxnfc = bnxt_set_rxnfc, 4177c0c050c5SMichael Chan .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 4178c0c050c5SMichael Chan .get_rxfh_key_size = bnxt_get_rxfh_key_size, 4179c0c050c5SMichael Chan .get_rxfh = bnxt_get_rxfh, 4180bd3191b5SMichael Chan .set_rxfh = bnxt_set_rxfh, 4181c0c050c5SMichael Chan .flash_device = bnxt_flash_device, 4182c0c050c5SMichael Chan .get_eeprom_len = bnxt_get_eeprom_len, 4183c0c050c5SMichael Chan .get_eeprom = bnxt_get_eeprom, 4184c0c050c5SMichael Chan .set_eeprom = bnxt_set_eeprom, 4185c0c050c5SMichael Chan .get_link = bnxt_get_link, 41869a0f830fSJakub Kicinski .get_link_ext_stats = bnxt_get_link_ext_stats, 418772b34f04SMichael Chan .get_eee = bnxt_get_eee, 418872b34f04SMichael Chan .set_eee = bnxt_set_eee, 418942ee18feSAjit Khaparde .get_module_info = bnxt_get_module_info, 419042ee18feSAjit Khaparde .get_module_eeprom = bnxt_get_module_eeprom, 41917ef3d390SVikas Gupta .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, 41925ad2cbeeSMichael Chan .nway_reset = bnxt_nway_reset, 41935ad2cbeeSMichael Chan .set_phys_id = bnxt_set_phys_id, 4194eb513658SMichael Chan .self_test = bnxt_self_test, 4195118612d5SMichael Chan .get_ts_info = bnxt_get_ts_info, 419649f7972fSVasundhara Volam .reset = bnxt_reset, 41970b0eacf3SVasundhara Volam .set_dump = bnxt_set_dump, 41986c5657d0SVasundhara Volam .get_dump_flag = bnxt_get_dump_flag, 41996c5657d0SVasundhara Volam .get_dump_data = bnxt_get_dump_data, 4200782bc00aSJakub Kicinski .get_eth_phy_stats = bnxt_get_eth_phy_stats, 4201782bc00aSJakub Kicinski .get_eth_mac_stats = bnxt_get_eth_mac_stats, 4202782bc00aSJakub Kicinski .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 4203782bc00aSJakub Kicinski .get_rmon_stats = bnxt_get_rmon_stats, 4204c0c050c5SMichael Chan }; 4205