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: 16551f30785SMichael Chan if (netif_running(dev)) { 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 1237a011952aSMichael Chan bp->rss_hash_cfg = rss_hash_cfg; 1238a011952aSMichael Chan if (netif_running(bp->dev)) { 1239a011952aSMichael Chan bnxt_close_nic(bp, false, false); 1240a011952aSMichael Chan rc = bnxt_open_nic(bp, false, false); 1241a011952aSMichael Chan } 1242a011952aSMichael Chan return rc; 1243a011952aSMichael Chan } 1244c0c050c5SMichael Chan 1245c0c050c5SMichael Chan static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 1246c0c050c5SMichael Chan u32 *rule_locs) 1247c0c050c5SMichael Chan { 1248c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1249c0c050c5SMichael Chan int rc = 0; 1250c0c050c5SMichael Chan 1251c0c050c5SMichael Chan switch (cmd->cmd) { 1252a011952aSMichael Chan #ifdef CONFIG_RFS_ACCEL 1253c0c050c5SMichael Chan case ETHTOOL_GRXRINGS: 1254c0c050c5SMichael Chan cmd->data = bp->rx_nr_rings; 1255c0c050c5SMichael Chan break; 1256c0c050c5SMichael Chan 1257c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLCNT: 1258c0c050c5SMichael Chan cmd->rule_cnt = bp->ntp_fltr_count; 1259c0c050c5SMichael Chan cmd->data = BNXT_NTP_FLTR_MAX_FLTR; 1260c0c050c5SMichael Chan break; 1261c0c050c5SMichael Chan 1262c0c050c5SMichael Chan case ETHTOOL_GRXCLSRLALL: 1263c0c050c5SMichael Chan rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs); 1264c0c050c5SMichael Chan break; 1265c0c050c5SMichael Chan 1266c0c050c5SMichael Chan case ETHTOOL_GRXCLSRULE: 1267c0c050c5SMichael Chan rc = bnxt_grxclsrule(bp, cmd); 1268c0c050c5SMichael Chan break; 1269a011952aSMichael Chan #endif 1270a011952aSMichael Chan 1271a011952aSMichael Chan case ETHTOOL_GRXFH: 1272a011952aSMichael Chan rc = bnxt_grxfh(bp, cmd); 1273a011952aSMichael Chan break; 1274c0c050c5SMichael Chan 1275c0c050c5SMichael Chan default: 1276c0c050c5SMichael Chan rc = -EOPNOTSUPP; 1277c0c050c5SMichael Chan break; 1278c0c050c5SMichael Chan } 1279c0c050c5SMichael Chan 1280c0c050c5SMichael Chan return rc; 1281c0c050c5SMichael Chan } 1282a011952aSMichael Chan 1283a011952aSMichael Chan static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 1284a011952aSMichael Chan { 1285a011952aSMichael Chan struct bnxt *bp = netdev_priv(dev); 1286a011952aSMichael Chan int rc; 1287a011952aSMichael Chan 1288a011952aSMichael Chan switch (cmd->cmd) { 1289a011952aSMichael Chan case ETHTOOL_SRXFH: 1290a011952aSMichael Chan rc = bnxt_srxfh(bp, cmd); 1291a011952aSMichael Chan break; 1292a011952aSMichael Chan 1293a011952aSMichael Chan default: 1294a011952aSMichael Chan rc = -EOPNOTSUPP; 1295a011952aSMichael Chan break; 1296a011952aSMichael Chan } 1297a011952aSMichael Chan return rc; 1298a011952aSMichael Chan } 1299c0c050c5SMichael Chan 1300b73c1d08SMichael Chan u32 bnxt_get_rxfh_indir_size(struct net_device *dev) 1301c0c050c5SMichael Chan { 1302b73c1d08SMichael Chan struct bnxt *bp = netdev_priv(dev); 1303b73c1d08SMichael Chan 1304b73c1d08SMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 1305b73c1d08SMichael Chan return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5); 1306c0c050c5SMichael Chan return HW_HASH_INDEX_SIZE; 1307c0c050c5SMichael Chan } 1308c0c050c5SMichael Chan 1309c0c050c5SMichael Chan static u32 bnxt_get_rxfh_key_size(struct net_device *dev) 1310c0c050c5SMichael Chan { 1311c0c050c5SMichael Chan return HW_HASH_KEY_SIZE; 1312c0c050c5SMichael Chan } 1313c0c050c5SMichael Chan 1314c0c050c5SMichael Chan static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 1315c0c050c5SMichael Chan u8 *hfunc) 1316c0c050c5SMichael Chan { 1317c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 13187991cb9cSMichael Chan struct bnxt_vnic_info *vnic; 1319adc38ac6SMichael Chan u32 i, tbl_size; 1320c0c050c5SMichael Chan 1321c0c050c5SMichael Chan if (hfunc) 1322c0c050c5SMichael Chan *hfunc = ETH_RSS_HASH_TOP; 1323c0c050c5SMichael Chan 13247991cb9cSMichael Chan if (!bp->vnic_info) 13257991cb9cSMichael Chan return 0; 13267991cb9cSMichael Chan 13277991cb9cSMichael Chan vnic = &bp->vnic_info[0]; 1328adc38ac6SMichael Chan if (indir && bp->rss_indir_tbl) { 1329adc38ac6SMichael Chan tbl_size = bnxt_get_rxfh_indir_size(dev); 1330adc38ac6SMichael Chan for (i = 0; i < tbl_size; i++) 1331adc38ac6SMichael Chan indir[i] = bp->rss_indir_tbl[i]; 13327991cb9cSMichael Chan } 1333c0c050c5SMichael Chan 13347991cb9cSMichael Chan if (key && vnic->rss_hash_key) 1335c0c050c5SMichael Chan memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); 1336c0c050c5SMichael Chan 1337c0c050c5SMichael Chan return 0; 1338c0c050c5SMichael Chan } 1339c0c050c5SMichael Chan 1340bd3191b5SMichael Chan static int bnxt_set_rxfh(struct net_device *dev, const u32 *indir, 1341bd3191b5SMichael Chan const u8 *key, const u8 hfunc) 1342bd3191b5SMichael Chan { 1343bd3191b5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1344bd3191b5SMichael Chan int rc = 0; 1345bd3191b5SMichael Chan 1346bd3191b5SMichael Chan if (hfunc && hfunc != ETH_RSS_HASH_TOP) 1347bd3191b5SMichael Chan return -EOPNOTSUPP; 1348bd3191b5SMichael Chan 1349bd3191b5SMichael Chan if (key) 1350bd3191b5SMichael Chan return -EOPNOTSUPP; 1351bd3191b5SMichael Chan 1352bd3191b5SMichael Chan if (indir) { 1353bd3191b5SMichael Chan u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); 1354bd3191b5SMichael Chan 1355bd3191b5SMichael Chan for (i = 0; i < tbl_size; i++) 1356bd3191b5SMichael Chan bp->rss_indir_tbl[i] = indir[i]; 1357bd3191b5SMichael Chan pad = bp->rss_indir_tbl_entries - tbl_size; 1358bd3191b5SMichael Chan if (pad) 1359bd3191b5SMichael Chan memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); 1360bd3191b5SMichael Chan } 1361bd3191b5SMichael Chan 1362bd3191b5SMichael Chan if (netif_running(bp->dev)) { 1363bd3191b5SMichael Chan bnxt_close_nic(bp, false, false); 1364bd3191b5SMichael Chan rc = bnxt_open_nic(bp, false, false); 1365bd3191b5SMichael Chan } 1366bd3191b5SMichael Chan return rc; 1367bd3191b5SMichael Chan } 1368bd3191b5SMichael Chan 1369c0c050c5SMichael Chan static void bnxt_get_drvinfo(struct net_device *dev, 1370c0c050c5SMichael Chan struct ethtool_drvinfo *info) 1371c0c050c5SMichael Chan { 1372c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1373c0c050c5SMichael Chan 1374f029c781SWolfram Sang strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 1375f029c781SWolfram Sang strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); 1376f029c781SWolfram Sang strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 13775c8227d0SMichael Chan info->n_stats = bnxt_get_num_stats(bp); 1378eb513658SMichael Chan info->testinfo_len = bp->num_tests; 1379c0c050c5SMichael Chan /* TODO CHIMP_FW: eeprom dump details */ 1380c0c050c5SMichael Chan info->eedump_len = 0; 1381c0c050c5SMichael Chan /* TODO CHIMP FW: reg dump details */ 1382c0c050c5SMichael Chan info->regdump_len = 0; 1383c0c050c5SMichael Chan } 1384c0c050c5SMichael Chan 1385b5d600b0SVasundhara Volam static int bnxt_get_regs_len(struct net_device *dev) 1386b5d600b0SVasundhara Volam { 1387b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1388b5d600b0SVasundhara Volam int reg_len; 1389b5d600b0SVasundhara Volam 1390f0f47b2fSVasundhara Volam if (!BNXT_PF(bp)) 1391f0f47b2fSVasundhara Volam return -EOPNOTSUPP; 1392f0f47b2fSVasundhara Volam 1393b5d600b0SVasundhara Volam reg_len = BNXT_PXP_REG_LEN; 1394b5d600b0SVasundhara Volam 1395b5d600b0SVasundhara Volam if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) 1396b5d600b0SVasundhara Volam reg_len += sizeof(struct pcie_ctx_hw_stats); 1397b5d600b0SVasundhara Volam 1398b5d600b0SVasundhara Volam return reg_len; 1399b5d600b0SVasundhara Volam } 1400b5d600b0SVasundhara Volam 1401b5d600b0SVasundhara Volam static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, 1402b5d600b0SVasundhara Volam void *_p) 1403b5d600b0SVasundhara Volam { 1404b5d600b0SVasundhara Volam struct pcie_ctx_hw_stats *hw_pcie_stats; 1405bbf33d1dSEdwin Peer struct hwrm_pcie_qstats_input *req; 1406b5d600b0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 1407b5d600b0SVasundhara Volam dma_addr_t hw_pcie_stats_addr; 1408b5d600b0SVasundhara Volam int rc; 1409b5d600b0SVasundhara Volam 1410b5d600b0SVasundhara Volam regs->version = 0; 1411b5d600b0SVasundhara Volam bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p); 1412b5d600b0SVasundhara Volam 1413b5d600b0SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) 1414b5d600b0SVasundhara Volam return; 1415b5d600b0SVasundhara Volam 1416bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) 1417b5d600b0SVasundhara Volam return; 1418b5d600b0SVasundhara Volam 1419bbf33d1dSEdwin Peer hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats), 1420bbf33d1dSEdwin Peer &hw_pcie_stats_addr); 1421bbf33d1dSEdwin Peer if (!hw_pcie_stats) { 1422bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1423bbf33d1dSEdwin Peer return; 1424bbf33d1dSEdwin Peer } 1425bbf33d1dSEdwin Peer 1426b5d600b0SVasundhara Volam regs->version = 1; 1427bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold on to slice */ 1428bbf33d1dSEdwin Peer req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); 1429bbf33d1dSEdwin Peer req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); 1430bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 1431b5d600b0SVasundhara Volam if (!rc) { 1432b5d600b0SVasundhara Volam __le64 *src = (__le64 *)hw_pcie_stats; 1433b5d600b0SVasundhara Volam u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); 1434b5d600b0SVasundhara Volam int i; 1435b5d600b0SVasundhara Volam 1436b5d600b0SVasundhara Volam for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) 1437b5d600b0SVasundhara Volam dst[i] = le64_to_cpu(src[i]); 1438b5d600b0SVasundhara Volam } 1439bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 1440b5d600b0SVasundhara Volam } 1441b5d600b0SVasundhara Volam 14428e202366SMichael Chan static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14438e202366SMichael Chan { 14448e202366SMichael Chan struct bnxt *bp = netdev_priv(dev); 14458e202366SMichael Chan 14468e202366SMichael Chan wol->supported = 0; 14478e202366SMichael Chan wol->wolopts = 0; 14488e202366SMichael Chan memset(&wol->sopass, 0, sizeof(wol->sopass)); 14498e202366SMichael Chan if (bp->flags & BNXT_FLAG_WOL_CAP) { 14508e202366SMichael Chan wol->supported = WAKE_MAGIC; 14518e202366SMichael Chan if (bp->wol) 14528e202366SMichael Chan wol->wolopts = WAKE_MAGIC; 14538e202366SMichael Chan } 14548e202366SMichael Chan } 14558e202366SMichael Chan 14565282db6cSMichael Chan static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14575282db6cSMichael Chan { 14585282db6cSMichael Chan struct bnxt *bp = netdev_priv(dev); 14595282db6cSMichael Chan 14605282db6cSMichael Chan if (wol->wolopts & ~WAKE_MAGIC) 14615282db6cSMichael Chan return -EINVAL; 14625282db6cSMichael Chan 14635282db6cSMichael Chan if (wol->wolopts & WAKE_MAGIC) { 14645282db6cSMichael Chan if (!(bp->flags & BNXT_FLAG_WOL_CAP)) 14655282db6cSMichael Chan return -EINVAL; 14665282db6cSMichael Chan if (!bp->wol) { 14675282db6cSMichael Chan if (bnxt_hwrm_alloc_wol_fltr(bp)) 14685282db6cSMichael Chan return -EBUSY; 14695282db6cSMichael Chan bp->wol = 1; 14705282db6cSMichael Chan } 14715282db6cSMichael Chan } else { 14725282db6cSMichael Chan if (bp->wol) { 14735282db6cSMichael Chan if (bnxt_hwrm_free_wol_fltr(bp)) 14745282db6cSMichael Chan return -EBUSY; 14755282db6cSMichael Chan bp->wol = 0; 14765282db6cSMichael Chan } 14775282db6cSMichael Chan } 14785282db6cSMichael Chan return 0; 14795282db6cSMichael Chan } 14805282db6cSMichael Chan 1481170ce013SMichael Chan u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) 1482c0c050c5SMichael Chan { 1483c0c050c5SMichael Chan u32 speed_mask = 0; 1484c0c050c5SMichael Chan 1485c0c050c5SMichael Chan /* TODO: support 25GB, 40GB, 50GB with different cable type */ 1486c0c050c5SMichael Chan /* set the advertised speeds */ 1487c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) 1488c0c050c5SMichael Chan speed_mask |= ADVERTISED_100baseT_Full; 1489c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) 1490c0c050c5SMichael Chan speed_mask |= ADVERTISED_1000baseT_Full; 1491c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) 1492c0c050c5SMichael Chan speed_mask |= ADVERTISED_2500baseX_Full; 1493c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) 1494c0c050c5SMichael Chan speed_mask |= ADVERTISED_10000baseT_Full; 1495c0c050c5SMichael Chan if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) 14961c49c421SMichael Chan speed_mask |= ADVERTISED_40000baseCR4_Full; 149727c4d578SMichael Chan 149827c4d578SMichael Chan if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH) 149927c4d578SMichael Chan speed_mask |= ADVERTISED_Pause; 150027c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_TX) 150127c4d578SMichael Chan speed_mask |= ADVERTISED_Asym_Pause; 150227c4d578SMichael Chan else if (fw_pause & BNXT_LINK_PAUSE_RX) 150327c4d578SMichael Chan speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 150427c4d578SMichael Chan 1505c0c050c5SMichael Chan return speed_mask; 1506c0c050c5SMichael Chan } 1507c0c050c5SMichael Chan 150800c04a92SMichael Chan #define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ 150900c04a92SMichael Chan { \ 151000c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ 151100c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151200c04a92SMichael Chan 100baseT_Full); \ 151300c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ 151400c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151500c04a92SMichael Chan 1000baseT_Full); \ 151600c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ 151700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 151800c04a92SMichael Chan 10000baseT_Full); \ 151900c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ 152000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152100c04a92SMichael Chan 25000baseCR_Full); \ 152200c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ 152300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152400c04a92SMichael Chan 40000baseCR4_Full);\ 152500c04a92SMichael Chan if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ 152600c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 152700c04a92SMichael Chan 50000baseCR2_Full);\ 152838a21b34SDeepak Khungar if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB) \ 152938a21b34SDeepak Khungar ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153038a21b34SDeepak Khungar 100000baseCR4_Full);\ 153100c04a92SMichael Chan if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ 153200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153300c04a92SMichael Chan Pause); \ 153400c04a92SMichael Chan if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ 153500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode( \ 153600c04a92SMichael Chan lk_ksettings, name, Asym_Pause);\ 153700c04a92SMichael Chan } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ 153800c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 153900c04a92SMichael Chan Asym_Pause); \ 154000c04a92SMichael Chan } \ 154100c04a92SMichael Chan } 154200c04a92SMichael Chan 154300c04a92SMichael Chan #define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ 154400c04a92SMichael Chan { \ 154500c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154600c04a92SMichael Chan 100baseT_Full) || \ 154700c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 154800c04a92SMichael Chan 100baseT_Half)) \ 154900c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ 155000c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155100c04a92SMichael Chan 1000baseT_Full) || \ 155200c04a92SMichael Chan ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155300c04a92SMichael Chan 1000baseT_Half)) \ 155400c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ 155500c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155600c04a92SMichael Chan 10000baseT_Full)) \ 155700c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ 155800c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 155900c04a92SMichael Chan 25000baseCR_Full)) \ 156000c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ 156100c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156200c04a92SMichael Chan 40000baseCR4_Full)) \ 156300c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ 156400c04a92SMichael Chan if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156500c04a92SMichael Chan 50000baseCR2_Full)) \ 156600c04a92SMichael Chan (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ 156738a21b34SDeepak Khungar if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 156838a21b34SDeepak Khungar 100000baseCR4_Full)) \ 156938a21b34SDeepak Khungar (fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB; \ 157000c04a92SMichael Chan } 157100c04a92SMichael Chan 1572532262baSEdwin Peer #define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1573532262baSEdwin Peer { \ 1574532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB) \ 1575532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1576532262baSEdwin Peer 50000baseCR_Full); \ 1577532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB) \ 1578532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1579532262baSEdwin Peer 100000baseCR2_Full);\ 1580532262baSEdwin Peer if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB) \ 1581532262baSEdwin Peer ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ 1582532262baSEdwin Peer 200000baseCR4_Full);\ 1583532262baSEdwin Peer } 1584532262baSEdwin Peer 1585532262baSEdwin Peer #define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name) \ 1586532262baSEdwin Peer { \ 1587532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1588532262baSEdwin Peer 50000baseCR_Full)) \ 1589532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB; \ 1590532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1591532262baSEdwin Peer 100000baseCR2_Full)) \ 1592532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB; \ 1593532262baSEdwin Peer if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ 1594532262baSEdwin Peer 200000baseCR4_Full)) \ 1595532262baSEdwin Peer (fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB; \ 1596532262baSEdwin Peer } 1597532262baSEdwin Peer 15988b277589SMichael Chan static void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, 15998b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16008b277589SMichael Chan { 16018b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16028b277589SMichael Chan 16038b277589SMichael Chan if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { 16048b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16058b277589SMichael Chan lk_ksettings->link_modes.advertising); 16068b277589SMichael Chan return; 16078b277589SMichael Chan } 16088b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 16098b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16108b277589SMichael Chan lk_ksettings->link_modes.advertising); 16118b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 16128b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16138b277589SMichael Chan lk_ksettings->link_modes.advertising); 16148b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 16158b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16168b277589SMichael Chan lk_ksettings->link_modes.advertising); 16178b277589SMichael Chan } 16188b277589SMichael Chan 161900c04a92SMichael Chan static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, 162000c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 162127c4d578SMichael Chan { 162268515a18SMichael Chan u16 fw_speeds = link_info->advertising; 162327c4d578SMichael Chan u8 fw_pause = 0; 162427c4d578SMichael Chan 162527c4d578SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 162627c4d578SMichael Chan fw_pause = link_info->auto_pause_setting; 162727c4d578SMichael Chan 162800c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); 1629532262baSEdwin Peer fw_speeds = link_info->advertising_pam4; 1630532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising); 16318b277589SMichael Chan bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); 163227c4d578SMichael Chan } 163327c4d578SMichael Chan 163400c04a92SMichael Chan static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, 163500c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16363277360eSMichael Chan { 16373277360eSMichael Chan u16 fw_speeds = link_info->lp_auto_link_speeds; 16383277360eSMichael Chan u8 fw_pause = 0; 16393277360eSMichael Chan 16403277360eSMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 16413277360eSMichael Chan fw_pause = link_info->lp_pause; 16423277360eSMichael Chan 164300c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, 164400c04a92SMichael Chan lp_advertising); 1645532262baSEdwin Peer fw_speeds = link_info->lp_auto_pam4_link_speeds; 1646532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising); 16473277360eSMichael Chan } 16483277360eSMichael Chan 16498b277589SMichael Chan static void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, 16508b277589SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16518b277589SMichael Chan { 16528b277589SMichael Chan u16 fec_cfg = link_info->fec_cfg; 16538b277589SMichael Chan 16548b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 16558b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, 16568b277589SMichael Chan lk_ksettings->link_modes.supported); 16578b277589SMichael Chan return; 16588b277589SMichael Chan } 16598b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) 16608b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, 16618b277589SMichael Chan lk_ksettings->link_modes.supported); 16628b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS_CAP) 16638b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, 16648b277589SMichael Chan lk_ksettings->link_modes.supported); 16658b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) 16668b277589SMichael Chan linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, 16678b277589SMichael Chan lk_ksettings->link_modes.supported); 16688b277589SMichael Chan } 16698b277589SMichael Chan 167000c04a92SMichael Chan static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, 167100c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 16724b32caccSMichael Chan { 16739a3bc77eSMichael Chan struct bnxt *bp = container_of(link_info, struct bnxt, link_info); 16744b32caccSMichael Chan u16 fw_speeds = link_info->support_speeds; 16754b32caccSMichael Chan 167600c04a92SMichael Chan BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); 1677532262baSEdwin Peer fw_speeds = link_info->support_pam4_speeds; 1678532262baSEdwin Peer BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported); 16794b32caccSMichael Chan 16809a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) { 16819a3bc77eSMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 16829a3bc77eSMichael Chan Pause); 168300c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 168400c04a92SMichael Chan Asym_Pause); 16859a3bc77eSMichael Chan } 168693ed8117SMichael Chan 1687532262baSEdwin Peer if (link_info->support_auto_speeds || 1688532262baSEdwin Peer link_info->support_pam4_auto_speeds) 168900c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 169000c04a92SMichael Chan Autoneg); 16918b277589SMichael Chan bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); 169293ed8117SMichael Chan } 169393ed8117SMichael Chan 1694c0c050c5SMichael Chan u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) 1695c0c050c5SMichael Chan { 1696c0c050c5SMichael Chan switch (fw_link_speed) { 1697c0c050c5SMichael Chan case BNXT_LINK_SPEED_100MB: 1698c0c050c5SMichael Chan return SPEED_100; 1699c0c050c5SMichael Chan case BNXT_LINK_SPEED_1GB: 1700c0c050c5SMichael Chan return SPEED_1000; 1701c0c050c5SMichael Chan case BNXT_LINK_SPEED_2_5GB: 1702c0c050c5SMichael Chan return SPEED_2500; 1703c0c050c5SMichael Chan case BNXT_LINK_SPEED_10GB: 1704c0c050c5SMichael Chan return SPEED_10000; 1705c0c050c5SMichael Chan case BNXT_LINK_SPEED_20GB: 1706c0c050c5SMichael Chan return SPEED_20000; 1707c0c050c5SMichael Chan case BNXT_LINK_SPEED_25GB: 1708c0c050c5SMichael Chan return SPEED_25000; 1709c0c050c5SMichael Chan case BNXT_LINK_SPEED_40GB: 1710c0c050c5SMichael Chan return SPEED_40000; 1711c0c050c5SMichael Chan case BNXT_LINK_SPEED_50GB: 1712c0c050c5SMichael Chan return SPEED_50000; 171338a21b34SDeepak Khungar case BNXT_LINK_SPEED_100GB: 171438a21b34SDeepak Khungar return SPEED_100000; 1715c0c050c5SMichael Chan default: 1716c0c050c5SMichael Chan return SPEED_UNKNOWN; 1717c0c050c5SMichael Chan } 1718c0c050c5SMichael Chan } 1719c0c050c5SMichael Chan 172000c04a92SMichael Chan static int bnxt_get_link_ksettings(struct net_device *dev, 172100c04a92SMichael Chan struct ethtool_link_ksettings *lk_ksettings) 1722c0c050c5SMichael Chan { 1723c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1724c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 172500c04a92SMichael Chan struct ethtool_link_settings *base = &lk_ksettings->base; 172600c04a92SMichael Chan u32 ethtool_speed; 1727c0c050c5SMichael Chan 172800c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); 1729e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 173000c04a92SMichael Chan bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); 1731c0c050c5SMichael Chan 173200c04a92SMichael Chan ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); 1733b763499eSMichael Chan if (link_info->autoneg) { 173400c04a92SMichael Chan bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); 173500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, 173600c04a92SMichael Chan advertising, Autoneg); 173700c04a92SMichael Chan base->autoneg = AUTONEG_ENABLE; 173800c04a92SMichael Chan base->duplex = DUPLEX_UNKNOWN; 173983d8f5e9SMichael Chan if (link_info->phy_link_status == BNXT_LINK_LINK) { 174083d8f5e9SMichael Chan bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); 174183d8f5e9SMichael Chan if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) 174200c04a92SMichael Chan base->duplex = DUPLEX_FULL; 174329c262feSMichael Chan else 174400c04a92SMichael Chan base->duplex = DUPLEX_HALF; 174583d8f5e9SMichael Chan } 174683d8f5e9SMichael Chan ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); 1747c0c050c5SMichael Chan } else { 174800c04a92SMichael Chan base->autoneg = AUTONEG_DISABLE; 174929c262feSMichael Chan ethtool_speed = 175029c262feSMichael Chan bnxt_fw_to_ethtool_speed(link_info->req_link_speed); 175100c04a92SMichael Chan base->duplex = DUPLEX_HALF; 175229c262feSMichael Chan if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) 175300c04a92SMichael Chan base->duplex = DUPLEX_FULL; 1754c0c050c5SMichael Chan } 175500c04a92SMichael Chan base->speed = ethtool_speed; 1756c0c050c5SMichael Chan 175700c04a92SMichael Chan base->port = PORT_NONE; 1758c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 175900c04a92SMichael Chan base->port = PORT_TP; 176000c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 176100c04a92SMichael Chan TP); 176200c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176300c04a92SMichael Chan TP); 1764c0c050c5SMichael Chan } else { 176500c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, 176600c04a92SMichael Chan FIBRE); 176700c04a92SMichael Chan ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, 176800c04a92SMichael Chan FIBRE); 1769c0c050c5SMichael Chan 1770c0c050c5SMichael Chan if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 177100c04a92SMichael Chan base->port = PORT_DA; 1772c0c050c5SMichael Chan else if (link_info->media_type == 1773c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) 177400c04a92SMichael Chan base->port = PORT_FIBRE; 1775c0c050c5SMichael Chan } 177600c04a92SMichael Chan base->phy_address = link_info->phy_addr; 1777e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1778c0c050c5SMichael Chan 1779c0c050c5SMichael Chan return 0; 1780c0c050c5SMichael Chan } 1781c0c050c5SMichael Chan 1782f00530bfSEdwin Peer static int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed) 1783c0c050c5SMichael Chan { 17849d9cee08SMichael Chan struct bnxt *bp = netdev_priv(dev); 17859d9cee08SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 1786532262baSEdwin Peer u16 support_pam4_spds = link_info->support_pam4_speeds; 17879d9cee08SMichael Chan u16 support_spds = link_info->support_speeds; 1788532262baSEdwin Peer u8 sig_mode = BNXT_SIG_MODE_NRZ; 1789f00530bfSEdwin Peer u16 fw_speed = 0; 17909d9cee08SMichael Chan 1791c0c050c5SMichael Chan switch (ethtool_speed) { 1792c0c050c5SMichael Chan case SPEED_100: 17939d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_100MB) 1794f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; 17959d9cee08SMichael Chan break; 1796c0c050c5SMichael Chan case SPEED_1000: 17979d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_1GB) 1798f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 17999d9cee08SMichael Chan break; 1800c0c050c5SMichael Chan case SPEED_2500: 18019d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) 1802f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; 18039d9cee08SMichael Chan break; 1804c0c050c5SMichael Chan case SPEED_10000: 18059d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_10GB) 1806f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 18079d9cee08SMichael Chan break; 1808c0c050c5SMichael Chan case SPEED_20000: 18099d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_20GB) 1810f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; 18119d9cee08SMichael Chan break; 1812c0c050c5SMichael Chan case SPEED_25000: 18139d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_25GB) 1814f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 18159d9cee08SMichael Chan break; 1816c0c050c5SMichael Chan case SPEED_40000: 18179d9cee08SMichael Chan if (support_spds & BNXT_LINK_SPEED_MSK_40GB) 1818f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 18199d9cee08SMichael Chan break; 1820c0c050c5SMichael Chan case SPEED_50000: 1821532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_50GB) { 1822f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 1823532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { 1824532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; 1825532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1826532262baSEdwin Peer } 18279d9cee08SMichael Chan break; 182838a21b34SDeepak Khungar case SPEED_100000: 1829532262baSEdwin Peer if (support_spds & BNXT_LINK_SPEED_MSK_100GB) { 1830f00530bfSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; 1831532262baSEdwin Peer } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { 1832532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; 1833532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1834532262baSEdwin Peer } 1835532262baSEdwin Peer break; 1836532262baSEdwin Peer case SPEED_200000: 1837532262baSEdwin Peer if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { 1838532262baSEdwin Peer fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; 1839532262baSEdwin Peer sig_mode = BNXT_SIG_MODE_PAM4; 1840532262baSEdwin Peer } 1841c0c050c5SMichael Chan break; 1842c0c050c5SMichael Chan } 1843f00530bfSEdwin Peer 1844f00530bfSEdwin Peer if (!fw_speed) { 1845f00530bfSEdwin Peer netdev_err(dev, "unsupported speed!\n"); 1846f00530bfSEdwin Peer return -EINVAL; 1847f00530bfSEdwin Peer } 1848f00530bfSEdwin Peer 1849745b5c65SEdwin Peer if (link_info->req_link_speed == fw_speed && 1850745b5c65SEdwin Peer link_info->req_signal_mode == sig_mode && 1851745b5c65SEdwin Peer link_info->autoneg == 0) 1852745b5c65SEdwin Peer return -EALREADY; 1853745b5c65SEdwin Peer 1854f00530bfSEdwin Peer link_info->req_link_speed = fw_speed; 1855532262baSEdwin Peer link_info->req_signal_mode = sig_mode; 1856f00530bfSEdwin Peer link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; 1857f00530bfSEdwin Peer link_info->autoneg = 0; 1858f00530bfSEdwin Peer link_info->advertising = 0; 1859532262baSEdwin Peer link_info->advertising_pam4 = 0; 1860f00530bfSEdwin Peer 1861f00530bfSEdwin Peer return 0; 1862c0c050c5SMichael Chan } 1863c0c050c5SMichael Chan 1864939f7f0cSMichael Chan u16 bnxt_get_fw_auto_link_speeds(u32 advertising) 1865c0c050c5SMichael Chan { 1866c0c050c5SMichael Chan u16 fw_speed_mask = 0; 1867c0c050c5SMichael Chan 1868c0c050c5SMichael Chan /* only support autoneg at speed 100, 1000, and 10000 */ 1869c0c050c5SMichael Chan if (advertising & (ADVERTISED_100baseT_Full | 1870c0c050c5SMichael Chan ADVERTISED_100baseT_Half)) { 1871c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; 1872c0c050c5SMichael Chan } 1873c0c050c5SMichael Chan if (advertising & (ADVERTISED_1000baseT_Full | 1874c0c050c5SMichael Chan ADVERTISED_1000baseT_Half)) { 1875c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; 1876c0c050c5SMichael Chan } 1877c0c050c5SMichael Chan if (advertising & ADVERTISED_10000baseT_Full) 1878c0c050c5SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; 1879c0c050c5SMichael Chan 18801c49c421SMichael Chan if (advertising & ADVERTISED_40000baseCR4_Full) 18811c49c421SMichael Chan fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; 18821c49c421SMichael Chan 1883c0c050c5SMichael Chan return fw_speed_mask; 1884c0c050c5SMichael Chan } 1885c0c050c5SMichael Chan 188600c04a92SMichael Chan static int bnxt_set_link_ksettings(struct net_device *dev, 188700c04a92SMichael Chan const struct ethtool_link_ksettings *lk_ksettings) 1888c0c050c5SMichael Chan { 1889c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 1890c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 189100c04a92SMichael Chan const struct ethtool_link_settings *base = &lk_ksettings->base; 1892c0c050c5SMichael Chan bool set_pause = false; 189368515a18SMichael Chan u32 speed; 189400c04a92SMichael Chan int rc = 0; 1895c0c050c5SMichael Chan 1896c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 189700c04a92SMichael Chan return -EOPNOTSUPP; 1898c0c050c5SMichael Chan 1899e2dc9b6eSMichael Chan mutex_lock(&bp->link_lock); 190000c04a92SMichael Chan if (base->autoneg == AUTONEG_ENABLE) { 1901532262baSEdwin Peer link_info->advertising = 0; 1902532262baSEdwin Peer link_info->advertising_pam4 = 0; 1903532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings, 190400c04a92SMichael Chan advertising); 1905532262baSEdwin Peer BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4, 1906532262baSEdwin Peer lk_ksettings, advertising); 1907c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_SPEED; 1908532262baSEdwin Peer if (!link_info->advertising && !link_info->advertising_pam4) { 190993ed8117SMichael Chan link_info->advertising = link_info->support_auto_speeds; 1910532262baSEdwin Peer link_info->advertising_pam4 = 1911532262baSEdwin Peer link_info->support_pam4_auto_speeds; 1912532262baSEdwin Peer } 1913c0c050c5SMichael Chan /* any change to autoneg will cause link change, therefore the 1914c0c050c5SMichael Chan * driver should put back the original pause setting in autoneg 1915c0c050c5SMichael Chan */ 19169a3bc77eSMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 1917c0c050c5SMichael Chan set_pause = true; 1918c0c050c5SMichael Chan } else { 191903efbec0SMichael Chan u8 phy_type = link_info->phy_type; 19209d9cee08SMichael Chan 192103efbec0SMichael Chan if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || 192203efbec0SMichael Chan phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || 192303efbec0SMichael Chan link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { 192403efbec0SMichael Chan netdev_err(dev, "10GBase-T devices must autoneg\n"); 192503efbec0SMichael Chan rc = -EINVAL; 192603efbec0SMichael Chan goto set_setting_exit; 192703efbec0SMichael Chan } 192800c04a92SMichael Chan if (base->duplex == DUPLEX_HALF) { 1929c0c050c5SMichael Chan netdev_err(dev, "HALF DUPLEX is not supported!\n"); 1930c0c050c5SMichael Chan rc = -EINVAL; 1931c0c050c5SMichael Chan goto set_setting_exit; 1932c0c050c5SMichael Chan } 193300c04a92SMichael Chan speed = base->speed; 1934f00530bfSEdwin Peer rc = bnxt_force_link_speed(dev, speed); 1935745b5c65SEdwin Peer if (rc) { 1936745b5c65SEdwin Peer if (rc == -EALREADY) 1937745b5c65SEdwin Peer rc = 0; 19389d9cee08SMichael Chan goto set_setting_exit; 19399d9cee08SMichael Chan } 1940745b5c65SEdwin Peer } 1941c0c050c5SMichael Chan 1942c0c050c5SMichael Chan if (netif_running(dev)) 1943939f7f0cSMichael Chan rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); 1944c0c050c5SMichael Chan 1945c0c050c5SMichael Chan set_setting_exit: 1946e2dc9b6eSMichael Chan mutex_unlock(&bp->link_lock); 1947c0c050c5SMichael Chan return rc; 1948c0c050c5SMichael Chan } 1949c0c050c5SMichael Chan 19508b277589SMichael Chan static int bnxt_get_fecparam(struct net_device *dev, 19518b277589SMichael Chan struct ethtool_fecparam *fec) 19528b277589SMichael Chan { 19538b277589SMichael Chan struct bnxt *bp = netdev_priv(dev); 19548b277589SMichael Chan struct bnxt_link_info *link_info; 19558b277589SMichael Chan u8 active_fec; 19568b277589SMichael Chan u16 fec_cfg; 19578b277589SMichael Chan 19588b277589SMichael Chan link_info = &bp->link_info; 19598b277589SMichael Chan fec_cfg = link_info->fec_cfg; 19608b277589SMichael Chan active_fec = link_info->active_fec_sig_mode & 19618b277589SMichael Chan PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; 19628b277589SMichael Chan if (fec_cfg & BNXT_FEC_NONE) { 19638b277589SMichael Chan fec->fec = ETHTOOL_FEC_NONE; 19648b277589SMichael Chan fec->active_fec = ETHTOOL_FEC_NONE; 19658b277589SMichael Chan return 0; 19668b277589SMichael Chan } 19678b277589SMichael Chan if (fec_cfg & BNXT_FEC_AUTONEG) 19688b277589SMichael Chan fec->fec |= ETHTOOL_FEC_AUTO; 19698b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_BASE_R) 19708b277589SMichael Chan fec->fec |= ETHTOOL_FEC_BASER; 19718b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_RS) 19728b277589SMichael Chan fec->fec |= ETHTOOL_FEC_RS; 19738b277589SMichael Chan if (fec_cfg & BNXT_FEC_ENC_LLRS) 19748b277589SMichael Chan fec->fec |= ETHTOOL_FEC_LLRS; 19758b277589SMichael Chan 19768b277589SMichael Chan switch (active_fec) { 19778b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: 19788b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_BASER; 19798b277589SMichael Chan break; 19808b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: 19818b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: 19828b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: 19838b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_RS; 19848b277589SMichael Chan break; 19858b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: 19868b277589SMichael Chan case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: 19878b277589SMichael Chan fec->active_fec |= ETHTOOL_FEC_LLRS; 19888b277589SMichael Chan break; 198984d3c83eSSomnath Kotur case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: 199084d3c83eSSomnath Kotur fec->active_fec |= ETHTOOL_FEC_OFF; 199184d3c83eSSomnath Kotur break; 19928b277589SMichael Chan } 19938b277589SMichael Chan return 0; 19948b277589SMichael Chan } 19958b277589SMichael Chan 1996c9ca5c3aSJakub Kicinski static void bnxt_get_fec_stats(struct net_device *dev, 1997c9ca5c3aSJakub Kicinski struct ethtool_fec_stats *fec_stats) 1998c9ca5c3aSJakub Kicinski { 1999c9ca5c3aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2000c9ca5c3aSJakub Kicinski u64 *rx; 2001c9ca5c3aSJakub Kicinski 2002c9ca5c3aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 2003c9ca5c3aSJakub Kicinski return; 2004c9ca5c3aSJakub Kicinski 2005c9ca5c3aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 2006c9ca5c3aSJakub Kicinski fec_stats->corrected_bits.total = 2007c9ca5c3aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); 2008c9ca5c3aSJakub Kicinski } 2009c9ca5c3aSJakub Kicinski 2010ccd6a9dcSMichael Chan static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, 2011ccd6a9dcSMichael Chan u32 fec) 2012ccd6a9dcSMichael Chan { 2013ccd6a9dcSMichael Chan u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; 2014ccd6a9dcSMichael Chan 2015ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_BASER) 2016ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_BASE_R_ON(link_info); 2017ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_RS) 2018ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_RS_ON(link_info); 2019ccd6a9dcSMichael Chan else if (fec & ETHTOOL_FEC_LLRS) 2020ccd6a9dcSMichael Chan fw_fec |= BNXT_FEC_LLRS_ON; 2021ccd6a9dcSMichael Chan return fw_fec; 2022ccd6a9dcSMichael Chan } 2023ccd6a9dcSMichael Chan 2024ccd6a9dcSMichael Chan static int bnxt_set_fecparam(struct net_device *dev, 2025ccd6a9dcSMichael Chan struct ethtool_fecparam *fecparam) 2026ccd6a9dcSMichael Chan { 2027bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 2028ccd6a9dcSMichael Chan struct bnxt *bp = netdev_priv(dev); 2029ccd6a9dcSMichael Chan struct bnxt_link_info *link_info; 2030ccd6a9dcSMichael Chan u32 new_cfg, fec = fecparam->fec; 2031ccd6a9dcSMichael Chan u16 fec_cfg; 2032ccd6a9dcSMichael Chan int rc; 2033ccd6a9dcSMichael Chan 2034ccd6a9dcSMichael Chan link_info = &bp->link_info; 2035ccd6a9dcSMichael Chan fec_cfg = link_info->fec_cfg; 2036ccd6a9dcSMichael Chan if (fec_cfg & BNXT_FEC_NONE) 2037ccd6a9dcSMichael Chan return -EOPNOTSUPP; 2038ccd6a9dcSMichael Chan 2039ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_OFF) { 2040ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | 2041ccd6a9dcSMichael Chan BNXT_FEC_ALL_OFF(link_info); 2042ccd6a9dcSMichael Chan goto apply_fec; 2043ccd6a9dcSMichael Chan } 2044ccd6a9dcSMichael Chan if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || 2045ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || 2046ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || 2047ccd6a9dcSMichael Chan ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) 2048ccd6a9dcSMichael Chan return -EINVAL; 2049ccd6a9dcSMichael Chan 2050ccd6a9dcSMichael Chan if (fec & ETHTOOL_FEC_AUTO) { 2051ccd6a9dcSMichael Chan if (!link_info->autoneg) 2052ccd6a9dcSMichael Chan return -EINVAL; 2053ccd6a9dcSMichael Chan new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; 2054ccd6a9dcSMichael Chan } else { 2055ccd6a9dcSMichael Chan new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); 2056ccd6a9dcSMichael Chan } 2057ccd6a9dcSMichael Chan 2058ccd6a9dcSMichael Chan apply_fec: 2059bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 2060bbf33d1dSEdwin Peer if (rc) 2061bbf33d1dSEdwin Peer return rc; 2062bbf33d1dSEdwin Peer req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 2063bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2064ccd6a9dcSMichael Chan /* update current settings */ 2065ccd6a9dcSMichael Chan if (!rc) { 2066ccd6a9dcSMichael Chan mutex_lock(&bp->link_lock); 2067ccd6a9dcSMichael Chan bnxt_update_link(bp, false); 2068ccd6a9dcSMichael Chan mutex_unlock(&bp->link_lock); 2069ccd6a9dcSMichael Chan } 2070ccd6a9dcSMichael Chan return rc; 2071ccd6a9dcSMichael Chan } 2072ccd6a9dcSMichael Chan 2073c0c050c5SMichael Chan static void bnxt_get_pauseparam(struct net_device *dev, 2074c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2075c0c050c5SMichael Chan { 2076c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2077c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2078c0c050c5SMichael Chan 2079c0c050c5SMichael Chan if (BNXT_VF(bp)) 2080c0c050c5SMichael Chan return; 2081b763499eSMichael Chan epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); 20823c02d1bbSMichael Chan epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); 20833c02d1bbSMichael Chan epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); 2084c0c050c5SMichael Chan } 2085c0c050c5SMichael Chan 2086423cffcfSJakub Kicinski static void bnxt_get_pause_stats(struct net_device *dev, 2087423cffcfSJakub Kicinski struct ethtool_pause_stats *epstat) 2088423cffcfSJakub Kicinski { 2089423cffcfSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 2090423cffcfSJakub Kicinski u64 *rx, *tx; 2091423cffcfSJakub Kicinski 2092423cffcfSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 2093423cffcfSJakub Kicinski return; 2094423cffcfSJakub Kicinski 2095423cffcfSJakub Kicinski rx = bp->port_stats.sw_stats; 2096423cffcfSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 2097423cffcfSJakub Kicinski 2098423cffcfSJakub Kicinski epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); 2099423cffcfSJakub Kicinski epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); 2100423cffcfSJakub Kicinski } 2101423cffcfSJakub Kicinski 2102c0c050c5SMichael Chan static int bnxt_set_pauseparam(struct net_device *dev, 2103c0c050c5SMichael Chan struct ethtool_pauseparam *epause) 2104c0c050c5SMichael Chan { 2105c0c050c5SMichael Chan int rc = 0; 2106c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2107c0c050c5SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 2108c0c050c5SMichael Chan 21099a3bc77eSMichael Chan if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) 211075362a3fSMichael Chan return -EOPNOTSUPP; 2111c0c050c5SMichael Chan 2112a5390690SMichael Chan mutex_lock(&bp->link_lock); 2113c0c050c5SMichael Chan if (epause->autoneg) { 2114a5390690SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 2115a5390690SMichael Chan rc = -EINVAL; 2116a5390690SMichael Chan goto pause_exit; 2117a5390690SMichael Chan } 2118b763499eSMichael Chan 2119c0c050c5SMichael Chan link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; 21207c492a25SMichael Chan link_info->req_flow_ctrl = 0; 2121c0c050c5SMichael Chan } else { 2122c0c050c5SMichael Chan /* when transition from auto pause to force pause, 2123c0c050c5SMichael Chan * force a link change 2124c0c050c5SMichael Chan */ 2125c0c050c5SMichael Chan if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) 2126c0c050c5SMichael Chan link_info->force_link_chng = true; 2127c0c050c5SMichael Chan link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; 2128c9ee9516SMichael Chan link_info->req_flow_ctrl = 0; 2129c0c050c5SMichael Chan } 2130c0c050c5SMichael Chan if (epause->rx_pause) 2131c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; 2132c0c050c5SMichael Chan 2133c0c050c5SMichael Chan if (epause->tx_pause) 2134c0c050c5SMichael Chan link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; 2135c0c050c5SMichael Chan 2136a5390690SMichael Chan if (netif_running(dev)) 2137c0c050c5SMichael Chan rc = bnxt_hwrm_set_pause(bp); 2138a5390690SMichael Chan 2139a5390690SMichael Chan pause_exit: 2140163e9ef6SVasundhara Volam mutex_unlock(&bp->link_lock); 2141c0c050c5SMichael Chan return rc; 2142c0c050c5SMichael Chan } 2143c0c050c5SMichael Chan 2144c0c050c5SMichael Chan static u32 bnxt_get_link(struct net_device *dev) 2145c0c050c5SMichael Chan { 2146c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2147c0c050c5SMichael Chan 2148c0c050c5SMichael Chan /* TODO: handle MF, VF, driver close case */ 21490f5a4841SEdwin Peer return BNXT_LINK_IS_UP(bp); 2150c0c050c5SMichael Chan } 2151c0c050c5SMichael Chan 21524933f675SVasundhara Volam int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, 21534933f675SVasundhara Volam struct hwrm_nvm_get_dev_info_output *nvm_dev_info) 21544933f675SVasundhara Volam { 2155bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_output *resp; 2156bbf33d1dSEdwin Peer struct hwrm_nvm_get_dev_info_input *req; 21574933f675SVasundhara Volam int rc; 21584933f675SVasundhara Volam 21590ae0a779SVasundhara Volam if (BNXT_VF(bp)) 21600ae0a779SVasundhara Volam return -EOPNOTSUPP; 21610ae0a779SVasundhara Volam 2162bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); 2163bbf33d1dSEdwin Peer if (rc) 2164bbf33d1dSEdwin Peer return rc; 2165bbf33d1dSEdwin Peer 2166bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 2167bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 21684933f675SVasundhara Volam if (!rc) 21694933f675SVasundhara Volam memcpy(nvm_dev_info, resp, sizeof(*resp)); 2170bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 21714933f675SVasundhara Volam return rc; 21724933f675SVasundhara Volam } 21734933f675SVasundhara Volam 2174b3b0ddd0SMichael Chan static void bnxt_print_admin_err(struct bnxt *bp) 2175b3b0ddd0SMichael Chan { 2176b3b0ddd0SMichael Chan netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n"); 2177b3b0ddd0SMichael Chan } 2178b3b0ddd0SMichael Chan 21795b6ff128Svikas int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 21804a5eaa2fSJakub Kicinski u16 ext, u16 *index, u32 *item_length, 21814a5eaa2fSJakub Kicinski u32 *data_length); 21824a5eaa2fSJakub Kicinski 21835b6ff128Svikas int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, 218493ff3435SPavan Chebbi u16 dir_ordinal, u16 dir_ext, u16 dir_attr, 218593ff3435SPavan Chebbi u32 dir_item_len, const u8 *data, 2186c0c050c5SMichael Chan size_t data_len) 2187c0c050c5SMichael Chan { 2188c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2189bbf33d1dSEdwin Peer struct hwrm_nvm_write_input *req; 2190c0c050c5SMichael Chan int rc; 2191c0c050c5SMichael Chan 2192bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); 2193bbf33d1dSEdwin Peer if (rc) 2194bbf33d1dSEdwin Peer return rc; 2195c0c050c5SMichael Chan 219693ff3435SPavan Chebbi if (data_len && data) { 2197bbf33d1dSEdwin Peer dma_addr_t dma_handle; 2198bbf33d1dSEdwin Peer u8 *kmem; 2199c0c050c5SMichael Chan 2200bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle); 2201bbf33d1dSEdwin Peer if (!kmem) { 2202bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2203c0c050c5SMichael Chan return -ENOMEM; 220493ff3435SPavan Chebbi } 2205c0c050c5SMichael Chan 2206bbf33d1dSEdwin Peer req->dir_data_length = cpu_to_le32(data_len); 2207bbf33d1dSEdwin Peer 2208bbf33d1dSEdwin Peer memcpy(kmem, data, data_len); 2209bbf33d1dSEdwin Peer req->host_src_addr = cpu_to_le64(dma_handle); 2210bbf33d1dSEdwin Peer } 2211bbf33d1dSEdwin Peer 2212bce9a0b7SEdwin Peer hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout); 2213bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(dir_type); 2214bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(dir_ordinal); 2215bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(dir_ext); 2216bbf33d1dSEdwin Peer req->dir_attr = cpu_to_le16(dir_attr); 2217bbf33d1dSEdwin Peer req->dir_item_length = cpu_to_le32(dir_item_len); 2218bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2219c0c050c5SMichael Chan 2220d4f1420dSMichael Chan if (rc == -EACCES) 2221b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2222c0c050c5SMichael Chan return rc; 2223c0c050c5SMichael Chan } 2224c0c050c5SMichael Chan 22258f6c5e4dSEdwin Peer int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, 222695fec034SEdwin Peer u8 self_reset, u8 flags) 2227d2d6318cSRob Swindell { 22287c675421SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 2229bbf33d1dSEdwin Peer struct hwrm_fw_reset_input *req; 22307c675421SVasundhara Volam int rc; 2231d2d6318cSRob Swindell 2232892a662fSEdwin Peer if (!bnxt_hwrm_reset_permitted(bp)) { 2233892a662fSEdwin Peer netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver"); 2234892a662fSEdwin Peer return -EPERM; 2235892a662fSEdwin Peer } 2236892a662fSEdwin Peer 2237bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_FW_RESET); 2238bbf33d1dSEdwin Peer if (rc) 2239bbf33d1dSEdwin Peer return rc; 2240d2d6318cSRob Swindell 2241bbf33d1dSEdwin Peer req->embedded_proc_type = proc_type; 2242bbf33d1dSEdwin Peer req->selfrst_status = self_reset; 2243bbf33d1dSEdwin Peer req->flags = flags; 224495fec034SEdwin Peer 22458cec0940SEdwin Peer if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { 2246bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 22478cec0940SEdwin Peer } else { 2248bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 224995fec034SEdwin Peer if (rc == -EACCES) 225095fec034SEdwin Peer bnxt_print_admin_err(bp); 22518cec0940SEdwin Peer } 225295fec034SEdwin Peer return rc; 225395fec034SEdwin Peer } 225495fec034SEdwin Peer 225594f17e89SEdwin Peer static int bnxt_firmware_reset(struct net_device *dev, 225694f17e89SEdwin Peer enum bnxt_nvm_directory_type dir_type) 225795fec034SEdwin Peer { 225895fec034SEdwin Peer u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; 225995fec034SEdwin Peer u8 proc_type, flags = 0; 226095fec034SEdwin Peer 2261d2d6318cSRob Swindell /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ 2262d2d6318cSRob Swindell /* (e.g. when firmware isn't already running) */ 2263d2d6318cSRob Swindell switch (dir_type) { 2264d2d6318cSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 2265d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE: 2266d2d6318cSRob Swindell case BNX_DIR_TYPE_BOOTCODE_2: 226795fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; 2268d2d6318cSRob Swindell /* Self-reset ChiMP upon next PCIe reset: */ 226995fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2270d2d6318cSRob Swindell break; 2271d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_FW: 2272d2d6318cSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 227395fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; 227408141e0bSRob Swindell /* Self-reset APE upon next PCIe reset: */ 227595fec034SEdwin Peer self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; 2276d2d6318cSRob Swindell break; 2277d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_FW: 2278d2d6318cSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 227995fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; 2280d2d6318cSRob Swindell break; 2281d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_FW: 2282d2d6318cSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 228395fec034SEdwin Peer proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; 2284d2d6318cSRob Swindell break; 2285d2d6318cSRob Swindell default: 2286d2d6318cSRob Swindell return -EINVAL; 2287d2d6318cSRob Swindell } 2288d2d6318cSRob Swindell 228995fec034SEdwin Peer return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); 2290d2d6318cSRob Swindell } 2291d2d6318cSRob Swindell 229294f17e89SEdwin Peer static int bnxt_firmware_reset_chip(struct net_device *dev) 229394f17e89SEdwin Peer { 229494f17e89SEdwin Peer struct bnxt *bp = netdev_priv(dev); 229594f17e89SEdwin Peer u8 flags = 0; 229694f17e89SEdwin Peer 229794f17e89SEdwin Peer if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) 229894f17e89SEdwin Peer flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; 229994f17e89SEdwin Peer 230094f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, 230194f17e89SEdwin Peer FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, 230294f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, 230394f17e89SEdwin Peer flags); 230494f17e89SEdwin Peer } 230594f17e89SEdwin Peer 230694f17e89SEdwin Peer static int bnxt_firmware_reset_ap(struct net_device *dev) 230794f17e89SEdwin Peer { 230894f17e89SEdwin Peer return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, 230994f17e89SEdwin Peer FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, 231094f17e89SEdwin Peer 0); 231194f17e89SEdwin Peer } 231294f17e89SEdwin Peer 2313c0c050c5SMichael Chan static int bnxt_flash_firmware(struct net_device *dev, 2314c0c050c5SMichael Chan u16 dir_type, 2315c0c050c5SMichael Chan const u8 *fw_data, 2316c0c050c5SMichael Chan size_t fw_size) 2317c0c050c5SMichael Chan { 2318c0c050c5SMichael Chan int rc = 0; 2319c0c050c5SMichael Chan u16 code_type; 2320c0c050c5SMichael Chan u32 stored_crc; 2321c0c050c5SMichael Chan u32 calculated_crc; 2322c0c050c5SMichael Chan struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data; 2323c0c050c5SMichael Chan 2324c0c050c5SMichael Chan switch (dir_type) { 2325c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2326c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2327c0c050c5SMichael Chan code_type = CODE_BOOT; 2328c0c050c5SMichael Chan break; 232993e0b4feSRob Swindell case BNX_DIR_TYPE_CHIMP_PATCH: 233093e0b4feSRob Swindell code_type = CODE_CHIMP_PATCH; 233193e0b4feSRob Swindell break; 23322731d70fSRob Swindell case BNX_DIR_TYPE_APE_FW: 23332731d70fSRob Swindell code_type = CODE_MCTP_PASSTHRU; 23342731d70fSRob Swindell break; 233593e0b4feSRob Swindell case BNX_DIR_TYPE_APE_PATCH: 233693e0b4feSRob Swindell code_type = CODE_APE_PATCH; 233793e0b4feSRob Swindell break; 233893e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_FW: 233993e0b4feSRob Swindell code_type = CODE_KONG_FW; 234093e0b4feSRob Swindell break; 234193e0b4feSRob Swindell case BNX_DIR_TYPE_KONG_PATCH: 234293e0b4feSRob Swindell code_type = CODE_KONG_PATCH; 234393e0b4feSRob Swindell break; 234493e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 234593e0b4feSRob Swindell code_type = CODE_BONO_FW; 234693e0b4feSRob Swindell break; 234793e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 234893e0b4feSRob Swindell code_type = CODE_BONO_PATCH; 234993e0b4feSRob Swindell break; 2350c0c050c5SMichael Chan default: 2351c0c050c5SMichael Chan netdev_err(dev, "Unsupported directory entry type: %u\n", 2352c0c050c5SMichael Chan dir_type); 2353c0c050c5SMichael Chan return -EINVAL; 2354c0c050c5SMichael Chan } 2355c0c050c5SMichael Chan if (fw_size < sizeof(struct bnxt_fw_header)) { 2356c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware file size: %u\n", 2357c0c050c5SMichael Chan (unsigned int)fw_size); 2358c0c050c5SMichael Chan return -EINVAL; 2359c0c050c5SMichael Chan } 2360c0c050c5SMichael Chan if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { 2361c0c050c5SMichael Chan netdev_err(dev, "Invalid firmware signature: %08X\n", 2362c0c050c5SMichael Chan le32_to_cpu(header->signature)); 2363c0c050c5SMichael Chan return -EINVAL; 2364c0c050c5SMichael Chan } 2365c0c050c5SMichael Chan if (header->code_type != code_type) { 2366c0c050c5SMichael Chan netdev_err(dev, "Expected firmware type: %d, read: %d\n", 2367c0c050c5SMichael Chan code_type, header->code_type); 2368c0c050c5SMichael Chan return -EINVAL; 2369c0c050c5SMichael Chan } 2370c0c050c5SMichael Chan if (header->device != DEVICE_CUMULUS_FAMILY) { 2371c0c050c5SMichael Chan netdev_err(dev, "Expected firmware device family %d, read: %d\n", 2372c0c050c5SMichael Chan DEVICE_CUMULUS_FAMILY, header->device); 2373c0c050c5SMichael Chan return -EINVAL; 2374c0c050c5SMichael Chan } 2375c0c050c5SMichael Chan /* Confirm the CRC32 checksum of the file: */ 2376c0c050c5SMichael Chan stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 2377c0c050c5SMichael Chan sizeof(stored_crc))); 2378c0c050c5SMichael Chan calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 2379c0c050c5SMichael Chan if (calculated_crc != stored_crc) { 2380c0c050c5SMichael Chan netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n", 2381c0c050c5SMichael Chan (unsigned long)stored_crc, 2382c0c050c5SMichael Chan (unsigned long)calculated_crc); 2383c0c050c5SMichael Chan return -EINVAL; 2384c0c050c5SMichael Chan } 2385c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2386bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 2387d2d6318cSRob Swindell if (rc == 0) /* Firmware update successful */ 2388d2d6318cSRob Swindell rc = bnxt_firmware_reset(dev, dir_type); 2389d2d6318cSRob Swindell 2390c0c050c5SMichael Chan return rc; 2391c0c050c5SMichael Chan } 2392c0c050c5SMichael Chan 23935ac67d8bSRob Swindell static int bnxt_flash_microcode(struct net_device *dev, 23945ac67d8bSRob Swindell u16 dir_type, 23955ac67d8bSRob Swindell const u8 *fw_data, 23965ac67d8bSRob Swindell size_t fw_size) 23975ac67d8bSRob Swindell { 23985ac67d8bSRob Swindell struct bnxt_ucode_trailer *trailer; 23995ac67d8bSRob Swindell u32 calculated_crc; 24005ac67d8bSRob Swindell u32 stored_crc; 24015ac67d8bSRob Swindell int rc = 0; 24025ac67d8bSRob Swindell 24035ac67d8bSRob Swindell if (fw_size < sizeof(struct bnxt_ucode_trailer)) { 24045ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode file size: %u\n", 24055ac67d8bSRob Swindell (unsigned int)fw_size); 24065ac67d8bSRob Swindell return -EINVAL; 24075ac67d8bSRob Swindell } 24085ac67d8bSRob Swindell trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - 24095ac67d8bSRob Swindell sizeof(*trailer))); 24105ac67d8bSRob Swindell if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { 24115ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer signature: %08X\n", 24125ac67d8bSRob Swindell le32_to_cpu(trailer->sig)); 24135ac67d8bSRob Swindell return -EINVAL; 24145ac67d8bSRob Swindell } 24155ac67d8bSRob Swindell if (le16_to_cpu(trailer->dir_type) != dir_type) { 24165ac67d8bSRob Swindell netdev_err(dev, "Expected microcode type: %d, read: %d\n", 24175ac67d8bSRob Swindell dir_type, le16_to_cpu(trailer->dir_type)); 24185ac67d8bSRob Swindell return -EINVAL; 24195ac67d8bSRob Swindell } 24205ac67d8bSRob Swindell if (le16_to_cpu(trailer->trailer_length) < 24215ac67d8bSRob Swindell sizeof(struct bnxt_ucode_trailer)) { 24225ac67d8bSRob Swindell netdev_err(dev, "Invalid microcode trailer length: %d\n", 24235ac67d8bSRob Swindell le16_to_cpu(trailer->trailer_length)); 24245ac67d8bSRob Swindell return -EINVAL; 24255ac67d8bSRob Swindell } 24265ac67d8bSRob Swindell 24275ac67d8bSRob Swindell /* Confirm the CRC32 checksum of the file: */ 24285ac67d8bSRob Swindell stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - 24295ac67d8bSRob Swindell sizeof(stored_crc))); 24305ac67d8bSRob Swindell calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); 24315ac67d8bSRob Swindell if (calculated_crc != stored_crc) { 24325ac67d8bSRob Swindell netdev_err(dev, 24335ac67d8bSRob Swindell "CRC32 (%08lX) does not match calculated: %08lX\n", 24345ac67d8bSRob Swindell (unsigned long)stored_crc, 24355ac67d8bSRob Swindell (unsigned long)calculated_crc); 24365ac67d8bSRob Swindell return -EINVAL; 24375ac67d8bSRob Swindell } 24385ac67d8bSRob Swindell rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2439bbf33d1dSEdwin Peer 0, 0, 0, fw_data, fw_size); 24405ac67d8bSRob Swindell 24415ac67d8bSRob Swindell return rc; 24425ac67d8bSRob Swindell } 24435ac67d8bSRob Swindell 2444c0c050c5SMichael Chan static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) 2445c0c050c5SMichael Chan { 2446c0c050c5SMichael Chan switch (dir_type) { 2447c0c050c5SMichael Chan case BNX_DIR_TYPE_CHIMP_PATCH: 2448c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE: 2449c0c050c5SMichael Chan case BNX_DIR_TYPE_BOOTCODE_2: 2450c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_FW: 2451c0c050c5SMichael Chan case BNX_DIR_TYPE_APE_PATCH: 2452c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_FW: 2453c0c050c5SMichael Chan case BNX_DIR_TYPE_KONG_PATCH: 245493e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_FW: 245593e0b4feSRob Swindell case BNX_DIR_TYPE_BONO_PATCH: 2456c0c050c5SMichael Chan return true; 2457c0c050c5SMichael Chan } 2458c0c050c5SMichael Chan 2459c0c050c5SMichael Chan return false; 2460c0c050c5SMichael Chan } 2461c0c050c5SMichael Chan 24625ac67d8bSRob Swindell static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) 2463c0c050c5SMichael Chan { 2464c0c050c5SMichael Chan switch (dir_type) { 2465c0c050c5SMichael Chan case BNX_DIR_TYPE_AVS: 2466c0c050c5SMichael Chan case BNX_DIR_TYPE_EXP_ROM_MBA: 2467c0c050c5SMichael Chan case BNX_DIR_TYPE_PCIE: 2468c0c050c5SMichael Chan case BNX_DIR_TYPE_TSCF_UCODE: 2469c0c050c5SMichael Chan case BNX_DIR_TYPE_EXT_PHY: 2470c0c050c5SMichael Chan case BNX_DIR_TYPE_CCM: 2471c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT: 2472c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: 2473c0c050c5SMichael Chan case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: 2474c0c050c5SMichael Chan return true; 2475c0c050c5SMichael Chan } 2476c0c050c5SMichael Chan 2477c0c050c5SMichael Chan return false; 2478c0c050c5SMichael Chan } 2479c0c050c5SMichael Chan 2480c0c050c5SMichael Chan static bool bnxt_dir_type_is_executable(u16 dir_type) 2481c0c050c5SMichael Chan { 2482c0c050c5SMichael Chan return bnxt_dir_type_is_ape_bin_format(dir_type) || 24835ac67d8bSRob Swindell bnxt_dir_type_is_other_exec_format(dir_type); 2484c0c050c5SMichael Chan } 2485c0c050c5SMichael Chan 2486c0c050c5SMichael Chan static int bnxt_flash_firmware_from_file(struct net_device *dev, 2487c0c050c5SMichael Chan u16 dir_type, 2488c0c050c5SMichael Chan const char *filename) 2489c0c050c5SMichael Chan { 2490c0c050c5SMichael Chan const struct firmware *fw; 2491c0c050c5SMichael Chan int rc; 2492c0c050c5SMichael Chan 2493c0c050c5SMichael Chan rc = request_firmware(&fw, filename, &dev->dev); 2494c0c050c5SMichael Chan if (rc != 0) { 2495c0c050c5SMichael Chan netdev_err(dev, "Error %d requesting firmware file: %s\n", 2496c0c050c5SMichael Chan rc, filename); 2497c0c050c5SMichael Chan return rc; 2498c0c050c5SMichael Chan } 2499ba425800SJason Yan if (bnxt_dir_type_is_ape_bin_format(dir_type)) 2500c0c050c5SMichael Chan rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size); 2501ba425800SJason Yan else if (bnxt_dir_type_is_other_exec_format(dir_type)) 25025ac67d8bSRob Swindell rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size); 2503c0c050c5SMichael Chan else 2504c0c050c5SMichael Chan rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, 2505bbf33d1dSEdwin Peer 0, 0, 0, fw->data, fw->size); 2506c0c050c5SMichael Chan release_firmware(fw); 2507c0c050c5SMichael Chan return rc; 2508c0c050c5SMichael Chan } 2509c0c050c5SMichael Chan 2510ab0bed4bSKalesh AP #define MSG_INTEGRITY_ERR "PKG install error : Data integrity on NVM" 2511ab0bed4bSKalesh AP #define MSG_INVALID_PKG "PKG install error : Invalid package" 2512ab0bed4bSKalesh AP #define MSG_AUTHENTICATION_ERR "PKG install error : Authentication error" 2513ab0bed4bSKalesh AP #define MSG_INVALID_DEV "PKG install error : Invalid device" 2514ab0bed4bSKalesh AP #define MSG_INTERNAL_ERR "PKG install error : Internal error" 2515ab0bed4bSKalesh AP #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" 2516ab0bed4bSKalesh AP #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" 2517*45034224SVikas Gupta #define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" 2518ab0bed4bSKalesh AP #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" 2519ab0bed4bSKalesh AP #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" 2520ab0bed4bSKalesh AP 2521ab0bed4bSKalesh AP static int nvm_update_err_to_stderr(struct net_device *dev, u8 result, 2522ab0bed4bSKalesh AP struct netlink_ext_ack *extack) 2523ab0bed4bSKalesh AP { 2524ab0bed4bSKalesh AP switch (result) { 2525ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER: 2526ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER: 2527ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR: 2528ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR: 2529ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND: 2530ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED: 2531ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INTEGRITY_ERR); 2532ab0bed4bSKalesh AP return -EINVAL; 2533ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE: 2534ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER: 2535ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE: 2536ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM: 2537ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH: 2538ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST: 2539ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER: 2540ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM: 2541ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM: 2542ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH: 2543ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE: 2544ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM: 2545ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM: 2546ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_PKG); 2547ab0bed4bSKalesh AP return -ENOPKG; 2548ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR: 2549ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_AUTHENTICATION_ERR); 2550ab0bed4bSKalesh AP return -EPERM; 2551ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV: 2552ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID: 2553ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR: 2554ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID: 2555ab0bed4bSKalesh AP case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM: 2556ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_DEV); 2557ab0bed4bSKalesh AP return -EOPNOTSUPP; 2558ab0bed4bSKalesh AP default: 2559ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_INTERNAL_ERR); 2560ab0bed4bSKalesh AP return -EIO; 2561ab0bed4bSKalesh AP } 2562ab0bed4bSKalesh AP } 2563ab0bed4bSKalesh AP 2564a86b313eSMichael Chan #define BNXT_PKG_DMA_SIZE 0x40000 2565a86b313eSMichael Chan #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) 2566a86b313eSMichael Chan #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) 2567a86b313eSMichael Chan 2568*45034224SVikas Gupta static int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, 2569*45034224SVikas Gupta struct netlink_ext_ack *extack) 2570*45034224SVikas Gupta { 2571*45034224SVikas Gupta u32 item_len; 2572*45034224SVikas Gupta int rc; 2573*45034224SVikas Gupta 2574*45034224SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 2575*45034224SVikas Gupta BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, 2576*45034224SVikas Gupta &item_len, NULL); 2577*45034224SVikas Gupta if (rc) { 2578*45034224SVikas Gupta BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 2579*45034224SVikas Gupta return rc; 2580*45034224SVikas Gupta } 2581*45034224SVikas Gupta 2582*45034224SVikas Gupta if (fw_size > item_len) { 2583*45034224SVikas Gupta rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE, 2584*45034224SVikas Gupta BNX_DIR_ORDINAL_FIRST, 0, 1, 2585*45034224SVikas Gupta round_up(fw_size, 4096), NULL, 0); 2586*45034224SVikas Gupta if (rc) { 2587*45034224SVikas Gupta BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); 2588*45034224SVikas Gupta return rc; 2589*45034224SVikas Gupta } 2590*45034224SVikas Gupta } 2591*45034224SVikas Gupta return 0; 2592*45034224SVikas Gupta } 2593*45034224SVikas Gupta 2594b44cfd4fSJacob Keller int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, 2595ab0bed4bSKalesh AP u32 install_type, struct netlink_ext_ack *extack) 2596c0c050c5SMichael Chan { 2597bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_input *install; 2598bbf33d1dSEdwin Peer struct hwrm_nvm_install_update_output *resp; 2599bbf33d1dSEdwin Peer struct hwrm_nvm_modify_input *modify; 2600a9094ba6SMichael Chan struct bnxt *bp = netdev_priv(dev); 26011432c3f6SPavan Chebbi bool defrag_attempted = false; 2602a9094ba6SMichael Chan dma_addr_t dma_handle; 2603a9094ba6SMichael Chan u8 *kmem = NULL; 2604a86b313eSMichael Chan u32 modify_len; 26055ac67d8bSRob Swindell u32 item_len; 26068e42aef0SKalesh AP u8 cmd_err; 26075ac67d8bSRob Swindell u16 index; 2608bbf33d1dSEdwin Peer int rc; 26095ac67d8bSRob Swindell 2610*45034224SVikas Gupta /* resize before flashing larger image than available space */ 2611*45034224SVikas Gupta rc = bnxt_resize_update_entry(dev, fw->size, extack); 2612*45034224SVikas Gupta if (rc) 2613*45034224SVikas Gupta return rc; 2614*45034224SVikas Gupta 26155ac67d8bSRob Swindell bnxt_hwrm_fw_set_time(bp); 26165ac67d8bSRob Swindell 2617bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); 2618bbf33d1dSEdwin Peer if (rc) 2619bbf33d1dSEdwin Peer return rc; 2620a9094ba6SMichael Chan 2621a86b313eSMichael Chan /* Try allocating a large DMA buffer first. Older fw will 2622a86b313eSMichael Chan * cause excessive NVRAM erases when using small blocks. 2623a86b313eSMichael Chan */ 2624a86b313eSMichael Chan modify_len = roundup_pow_of_two(fw->size); 2625a86b313eSMichael Chan modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); 2626a86b313eSMichael Chan while (1) { 2627bbf33d1dSEdwin Peer kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle); 2628a86b313eSMichael Chan if (!kmem && modify_len > PAGE_SIZE) 2629a86b313eSMichael Chan modify_len /= 2; 2630a86b313eSMichael Chan else 2631a86b313eSMichael Chan break; 2632a86b313eSMichael Chan } 2633bbf33d1dSEdwin Peer if (!kmem) { 2634bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2635a9094ba6SMichael Chan return -ENOMEM; 2636bbf33d1dSEdwin Peer } 2637a9094ba6SMichael Chan 2638bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); 2639bbf33d1dSEdwin Peer if (rc) { 2640bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2641bbf33d1dSEdwin Peer return rc; 2642bbf33d1dSEdwin Peer } 2643a9094ba6SMichael Chan 2644bce9a0b7SEdwin Peer hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout); 2645bce9a0b7SEdwin Peer hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout); 2646bbf33d1dSEdwin Peer 2647bbf33d1dSEdwin Peer hwrm_req_hold(bp, modify); 2648bbf33d1dSEdwin Peer modify->host_src_addr = cpu_to_le64(dma_handle); 2649bbf33d1dSEdwin Peer 2650bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, install); 2651a9094ba6SMichael Chan if ((install_type & 0xffff) == 0) 2652a9094ba6SMichael Chan install_type >>= 16; 2653bbf33d1dSEdwin Peer install->install_type = cpu_to_le32(install_type); 2654a9094ba6SMichael Chan 26552e5fb428SPavan Chebbi do { 2656a86b313eSMichael Chan u32 copied = 0, len = modify_len; 2657a86b313eSMichael Chan 265895ec1f47SVasundhara Volam rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, 26592e5fb428SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 26602e5fb428SPavan Chebbi BNX_DIR_EXT_NONE, 266195ec1f47SVasundhara Volam &index, &item_len, NULL); 266295ec1f47SVasundhara Volam if (rc) { 2663ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); 26642e5fb428SPavan Chebbi break; 26655ac67d8bSRob Swindell } 26665ac67d8bSRob Swindell if (fw->size > item_len) { 2667ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_SPACE_ERR); 26685ac67d8bSRob Swindell rc = -EFBIG; 26692e5fb428SPavan Chebbi break; 26702e5fb428SPavan Chebbi } 26712e5fb428SPavan Chebbi 2672bbf33d1dSEdwin Peer modify->dir_idx = cpu_to_le16(index); 26735ac67d8bSRob Swindell 2674a86b313eSMichael Chan if (fw->size > modify_len) 2675bbf33d1dSEdwin Peer modify->flags = BNXT_NVM_MORE_FLAG; 2676a86b313eSMichael Chan while (copied < fw->size) { 2677a86b313eSMichael Chan u32 balance = fw->size - copied; 2678a86b313eSMichael Chan 2679a86b313eSMichael Chan if (balance <= modify_len) { 2680a86b313eSMichael Chan len = balance; 2681a86b313eSMichael Chan if (copied) 2682bbf33d1dSEdwin Peer modify->flags |= BNXT_NVM_LAST_FLAG; 2683a86b313eSMichael Chan } 2684a86b313eSMichael Chan memcpy(kmem, fw->data + copied, len); 2685bbf33d1dSEdwin Peer modify->len = cpu_to_le32(len); 2686bbf33d1dSEdwin Peer modify->offset = cpu_to_le32(copied); 2687bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, modify); 268822630e28SEdwin Peer if (rc) 2689a86b313eSMichael Chan goto pkg_abort; 2690a86b313eSMichael Chan copied += len; 2691a86b313eSMichael Chan } 2692bbf33d1dSEdwin Peer 2693bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 26948e42aef0SKalesh AP if (!rc) 26958e42aef0SKalesh AP break; 2696cb4d1d62SKshitij Soni 26971432c3f6SPavan Chebbi if (defrag_attempted) { 26981432c3f6SPavan Chebbi /* We have tried to defragment already in the previous 26991432c3f6SPavan Chebbi * iteration. Return with the result for INSTALL_UPDATE 27001432c3f6SPavan Chebbi */ 27011432c3f6SPavan Chebbi break; 27021432c3f6SPavan Chebbi } 27031432c3f6SPavan Chebbi 27048e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 27058e42aef0SKalesh AP 27068e42aef0SKalesh AP switch (cmd_err) { 270754ff1e3eSKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: 2708ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_ANTI_ROLLBACK_ERR); 270954ff1e3eSKalesh AP rc = -EALREADY; 271054ff1e3eSKalesh AP break; 27118e42aef0SKalesh AP case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: 2712bbf33d1dSEdwin Peer install->flags = 27132e5fb428SPavan Chebbi cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); 27142e5fb428SPavan Chebbi 2715bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, install); 27168e42aef0SKalesh AP if (!rc) 27178e42aef0SKalesh AP break; 27181432c3f6SPavan Chebbi 27198e42aef0SKalesh AP cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; 27208e42aef0SKalesh AP 27218e42aef0SKalesh AP if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { 27221432c3f6SPavan Chebbi /* FW has cleared NVM area, driver will create 27231432c3f6SPavan Chebbi * UPDATE directory and try the flash again 27241432c3f6SPavan Chebbi */ 27251432c3f6SPavan Chebbi defrag_attempted = true; 2726bbf33d1dSEdwin Peer install->flags = 0; 2727bbf33d1dSEdwin Peer rc = bnxt_flash_nvram(bp->dev, 27281432c3f6SPavan Chebbi BNX_DIR_TYPE_UPDATE, 27291432c3f6SPavan Chebbi BNX_DIR_ORDINAL_FIRST, 2730bbf33d1dSEdwin Peer 0, 0, item_len, NULL, 0); 27318e42aef0SKalesh AP if (!rc) 27328e42aef0SKalesh AP break; 27331432c3f6SPavan Chebbi } 27348e42aef0SKalesh AP fallthrough; 27358e42aef0SKalesh AP default: 2736ab0bed4bSKalesh AP BNXT_NVM_ERR_MSG(dev, extack, MSG_GENERIC_FAILURE_ERR); 2737dd2ebf34SVasundhara Volam } 27381432c3f6SPavan Chebbi } while (defrag_attempted && !rc); 27395ac67d8bSRob Swindell 2740a86b313eSMichael Chan pkg_abort: 2741bbf33d1dSEdwin Peer hwrm_req_drop(bp, modify); 2742bbf33d1dSEdwin Peer hwrm_req_drop(bp, install); 2743bbf33d1dSEdwin Peer 2744bbf33d1dSEdwin Peer if (resp->result) { 27455ac67d8bSRob Swindell netdev_err(dev, "PKG install error = %d, problem_item = %d\n", 2746bbf33d1dSEdwin Peer (s8)resp->result, (int)resp->problem_item); 2747ab0bed4bSKalesh AP rc = nvm_update_err_to_stderr(dev, resp->result, extack); 27485ac67d8bSRob Swindell } 274922630e28SEdwin Peer if (rc == -EACCES) 2750b3b0ddd0SMichael Chan bnxt_print_admin_err(bp); 2751cb4d1d62SKshitij Soni return rc; 2752c0c050c5SMichael Chan } 2753c0c050c5SMichael Chan 2754b44cfd4fSJacob Keller static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, 2755ab0bed4bSKalesh AP u32 install_type, struct netlink_ext_ack *extack) 2756b44cfd4fSJacob Keller { 2757b44cfd4fSJacob Keller const struct firmware *fw; 2758b44cfd4fSJacob Keller int rc; 2759b44cfd4fSJacob Keller 2760b44cfd4fSJacob Keller rc = request_firmware(&fw, filename, &dev->dev); 2761b44cfd4fSJacob Keller if (rc != 0) { 2762b44cfd4fSJacob Keller netdev_err(dev, "PKG error %d requesting file: %s\n", 2763b44cfd4fSJacob Keller rc, filename); 2764b44cfd4fSJacob Keller return rc; 2765b44cfd4fSJacob Keller } 2766b44cfd4fSJacob Keller 2767ab0bed4bSKalesh AP rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type, extack); 2768b44cfd4fSJacob Keller 2769b44cfd4fSJacob Keller release_firmware(fw); 2770b44cfd4fSJacob Keller 2771b44cfd4fSJacob Keller return rc; 2772b44cfd4fSJacob Keller } 2773b44cfd4fSJacob Keller 2774c0c050c5SMichael Chan static int bnxt_flash_device(struct net_device *dev, 2775c0c050c5SMichael Chan struct ethtool_flash *flash) 2776c0c050c5SMichael Chan { 2777c0c050c5SMichael Chan if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { 2778c0c050c5SMichael Chan netdev_err(dev, "flashdev not supported from a virtual function\n"); 2779c0c050c5SMichael Chan return -EINVAL; 2780c0c050c5SMichael Chan } 2781c0c050c5SMichael Chan 27825ac67d8bSRob Swindell if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || 27835ac67d8bSRob Swindell flash->region > 0xffff) 27845ac67d8bSRob Swindell return bnxt_flash_package_from_file(dev, flash->data, 2785ab0bed4bSKalesh AP flash->region, NULL); 2786c0c050c5SMichael Chan 2787c0c050c5SMichael Chan return bnxt_flash_firmware_from_file(dev, flash->region, flash->data); 2788c0c050c5SMichael Chan } 2789c0c050c5SMichael Chan 2790c0c050c5SMichael Chan static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) 2791c0c050c5SMichael Chan { 2792bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_output *output; 2793bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_info_input *req; 2794c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2795c0c050c5SMichael Chan int rc; 2796c0c050c5SMichael Chan 2797bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); 2798bbf33d1dSEdwin Peer if (rc) 2799bbf33d1dSEdwin Peer return rc; 2800c0c050c5SMichael Chan 2801bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2802bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2803c0c050c5SMichael Chan if (!rc) { 2804c0c050c5SMichael Chan *entries = le32_to_cpu(output->entries); 2805c0c050c5SMichael Chan *length = le32_to_cpu(output->entry_length); 2806c0c050c5SMichael Chan } 2807bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2808c0c050c5SMichael Chan return rc; 2809c0c050c5SMichael Chan } 2810c0c050c5SMichael Chan 2811c0c050c5SMichael Chan static int bnxt_get_eeprom_len(struct net_device *dev) 2812c0c050c5SMichael Chan { 28134cebbacaSMichael Chan struct bnxt *bp = netdev_priv(dev); 28144cebbacaSMichael Chan 28154cebbacaSMichael Chan if (BNXT_VF(bp)) 28164cebbacaSMichael Chan return 0; 28174cebbacaSMichael Chan 2818c0c050c5SMichael Chan /* The -1 return value allows the entire 32-bit range of offsets to be 2819c0c050c5SMichael Chan * passed via the ethtool command-line utility. 2820c0c050c5SMichael Chan */ 2821c0c050c5SMichael Chan return -1; 2822c0c050c5SMichael Chan } 2823c0c050c5SMichael Chan 2824c0c050c5SMichael Chan static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) 2825c0c050c5SMichael Chan { 2826c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2827c0c050c5SMichael Chan int rc; 2828c0c050c5SMichael Chan u32 dir_entries; 2829c0c050c5SMichael Chan u32 entry_length; 2830c0c050c5SMichael Chan u8 *buf; 2831c0c050c5SMichael Chan size_t buflen; 2832c0c050c5SMichael Chan dma_addr_t dma_handle; 2833bbf33d1dSEdwin Peer struct hwrm_nvm_get_dir_entries_input *req; 2834c0c050c5SMichael Chan 2835c0c050c5SMichael Chan rc = nvm_get_dir_info(dev, &dir_entries, &entry_length); 2836c0c050c5SMichael Chan if (rc != 0) 2837c0c050c5SMichael Chan return rc; 2838c0c050c5SMichael Chan 2839dbbfa96aSVasundhara Volam if (!dir_entries || !entry_length) 2840dbbfa96aSVasundhara Volam return -EIO; 2841dbbfa96aSVasundhara Volam 2842c0c050c5SMichael Chan /* Insert 2 bytes of directory info (count and size of entries) */ 2843c0c050c5SMichael Chan if (len < 2) 2844c0c050c5SMichael Chan return -EINVAL; 2845c0c050c5SMichael Chan 2846c0c050c5SMichael Chan *data++ = dir_entries; 2847c0c050c5SMichael Chan *data++ = entry_length; 2848c0c050c5SMichael Chan len -= 2; 2849c0c050c5SMichael Chan memset(data, 0xff, len); 2850c0c050c5SMichael Chan 2851bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); 2852bbf33d1dSEdwin Peer if (rc) 2853bbf33d1dSEdwin Peer return rc; 2854bbf33d1dSEdwin Peer 2855c0c050c5SMichael Chan buflen = dir_entries * entry_length; 2856bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle); 2857c0c050c5SMichael Chan if (!buf) { 2858bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2859c0c050c5SMichael Chan return -ENOMEM; 2860c0c050c5SMichael Chan } 2861bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2862bbf33d1dSEdwin Peer 2863bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2864bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2865c0c050c5SMichael Chan if (rc == 0) 2866c0c050c5SMichael Chan memcpy(data, buf, len > buflen ? buflen : len); 2867bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2868c0c050c5SMichael Chan return rc; 2869c0c050c5SMichael Chan } 2870c0c050c5SMichael Chan 28715b6ff128Svikas int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, 2872c0c050c5SMichael Chan u32 length, u8 *data) 2873c0c050c5SMichael Chan { 2874c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 2875c0c050c5SMichael Chan int rc; 2876c0c050c5SMichael Chan u8 *buf; 2877c0c050c5SMichael Chan dma_addr_t dma_handle; 2878bbf33d1dSEdwin Peer struct hwrm_nvm_read_input *req; 2879c0c050c5SMichael Chan 2880e0ad8fc5SMichael Chan if (!length) 2881e0ad8fc5SMichael Chan return -EINVAL; 2882e0ad8fc5SMichael Chan 2883bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_READ); 2884bbf33d1dSEdwin Peer if (rc) 2885bbf33d1dSEdwin Peer return rc; 2886bbf33d1dSEdwin Peer 2887bbf33d1dSEdwin Peer buf = hwrm_req_dma_slice(bp, req, length, &dma_handle); 2888c0c050c5SMichael Chan if (!buf) { 2889bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2890c0c050c5SMichael Chan return -ENOMEM; 2891c0c050c5SMichael Chan } 2892c0c050c5SMichael Chan 2893bbf33d1dSEdwin Peer req->host_dest_addr = cpu_to_le64(dma_handle); 2894bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 2895bbf33d1dSEdwin Peer req->offset = cpu_to_le32(offset); 2896bbf33d1dSEdwin Peer req->len = cpu_to_le32(length); 2897bbf33d1dSEdwin Peer 2898bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); /* hold the slice */ 2899bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 2900c0c050c5SMichael Chan if (rc == 0) 2901c0c050c5SMichael Chan memcpy(data, buf, length); 2902bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 2903c0c050c5SMichael Chan return rc; 2904c0c050c5SMichael Chan } 2905c0c050c5SMichael Chan 29065b6ff128Svikas int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, 29073ebf6f0aSRob Swindell u16 ext, u16 *index, u32 *item_length, 29083ebf6f0aSRob Swindell u32 *data_length) 29093ebf6f0aSRob Swindell { 2910bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_output *output; 2911bbf33d1dSEdwin Peer struct hwrm_nvm_find_dir_entry_input *req; 29123ebf6f0aSRob Swindell struct bnxt *bp = netdev_priv(dev); 29133ebf6f0aSRob Swindell int rc; 29143ebf6f0aSRob Swindell 2915bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); 2916bbf33d1dSEdwin Peer if (rc) 2917bbf33d1dSEdwin Peer return rc; 2918bbf33d1dSEdwin Peer 2919bbf33d1dSEdwin Peer req->enables = 0; 2920bbf33d1dSEdwin Peer req->dir_idx = 0; 2921bbf33d1dSEdwin Peer req->dir_type = cpu_to_le16(type); 2922bbf33d1dSEdwin Peer req->dir_ordinal = cpu_to_le16(ordinal); 2923bbf33d1dSEdwin Peer req->dir_ext = cpu_to_le16(ext); 2924bbf33d1dSEdwin Peer req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; 2925bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 2926bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 29273ebf6f0aSRob Swindell if (rc == 0) { 29283ebf6f0aSRob Swindell if (index) 29293ebf6f0aSRob Swindell *index = le16_to_cpu(output->dir_idx); 29303ebf6f0aSRob Swindell if (item_length) 29313ebf6f0aSRob Swindell *item_length = le32_to_cpu(output->dir_item_length); 29323ebf6f0aSRob Swindell if (data_length) 29333ebf6f0aSRob Swindell *data_length = le32_to_cpu(output->dir_data_length); 29343ebf6f0aSRob Swindell } 2935bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 29363ebf6f0aSRob Swindell return rc; 29373ebf6f0aSRob Swindell } 29383ebf6f0aSRob Swindell 29393ebf6f0aSRob Swindell static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) 29403ebf6f0aSRob Swindell { 29413ebf6f0aSRob Swindell char *retval = NULL; 29423ebf6f0aSRob Swindell char *p; 29433ebf6f0aSRob Swindell char *value; 29443ebf6f0aSRob Swindell int field = 0; 29453ebf6f0aSRob Swindell 29463ebf6f0aSRob Swindell if (datalen < 1) 29473ebf6f0aSRob Swindell return NULL; 29483ebf6f0aSRob Swindell /* null-terminate the log data (removing last '\n'): */ 29493ebf6f0aSRob Swindell data[datalen - 1] = 0; 29503ebf6f0aSRob Swindell for (p = data; *p != 0; p++) { 29513ebf6f0aSRob Swindell field = 0; 29523ebf6f0aSRob Swindell retval = NULL; 29533ebf6f0aSRob Swindell while (*p != 0 && *p != '\n') { 29543ebf6f0aSRob Swindell value = p; 29553ebf6f0aSRob Swindell while (*p != 0 && *p != '\t' && *p != '\n') 29563ebf6f0aSRob Swindell p++; 29573ebf6f0aSRob Swindell if (field == desired_field) 29583ebf6f0aSRob Swindell retval = value; 29593ebf6f0aSRob Swindell if (*p != '\t') 29603ebf6f0aSRob Swindell break; 29613ebf6f0aSRob Swindell *p = 0; 29623ebf6f0aSRob Swindell field++; 29633ebf6f0aSRob Swindell p++; 29643ebf6f0aSRob Swindell } 29653ebf6f0aSRob Swindell if (*p == 0) 29663ebf6f0aSRob Swindell break; 29673ebf6f0aSRob Swindell *p = 0; 29683ebf6f0aSRob Swindell } 29693ebf6f0aSRob Swindell return retval; 29703ebf6f0aSRob Swindell } 29713ebf6f0aSRob Swindell 297263185eb3SVikas Gupta int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) 29733ebf6f0aSRob Swindell { 2974a60faa60SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 29753ebf6f0aSRob Swindell u16 index = 0; 2976a60faa60SVasundhara Volam char *pkgver; 2977a60faa60SVasundhara Volam u32 pkglen; 2978a60faa60SVasundhara Volam u8 *pkgbuf; 297963185eb3SVikas Gupta int rc; 29803ebf6f0aSRob Swindell 298163185eb3SVikas Gupta rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG, 29823ebf6f0aSRob Swindell BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, 298363185eb3SVikas Gupta &index, NULL, &pkglen); 298463185eb3SVikas Gupta if (rc) 298563185eb3SVikas Gupta return rc; 29863ebf6f0aSRob Swindell 2987a60faa60SVasundhara Volam pkgbuf = kzalloc(pkglen, GFP_KERNEL); 2988a60faa60SVasundhara Volam if (!pkgbuf) { 2989a60faa60SVasundhara Volam dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n", 2990a60faa60SVasundhara Volam pkglen); 299163185eb3SVikas Gupta return -ENOMEM; 2992a60faa60SVasundhara Volam } 29933ebf6f0aSRob Swindell 299463185eb3SVikas Gupta rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf); 299563185eb3SVikas Gupta if (rc) 2996a60faa60SVasundhara Volam goto err; 2997a60faa60SVasundhara Volam 2998a60faa60SVasundhara Volam pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf, 2999a60faa60SVasundhara Volam pkglen); 300063185eb3SVikas Gupta if (pkgver && *pkgver != 0 && isdigit(*pkgver)) 300163185eb3SVikas Gupta strscpy(ver, pkgver, size); 300263185eb3SVikas Gupta else 300363185eb3SVikas Gupta rc = -ENOENT; 300463185eb3SVikas Gupta 3005a60faa60SVasundhara Volam err: 3006a60faa60SVasundhara Volam kfree(pkgbuf); 300763185eb3SVikas Gupta 300863185eb3SVikas Gupta return rc; 300963185eb3SVikas Gupta } 301063185eb3SVikas Gupta 301163185eb3SVikas Gupta static void bnxt_get_pkgver(struct net_device *dev) 301263185eb3SVikas Gupta { 301363185eb3SVikas Gupta struct bnxt *bp = netdev_priv(dev); 301463185eb3SVikas Gupta char buf[FW_VER_STR_LEN]; 301563185eb3SVikas Gupta int len; 301663185eb3SVikas Gupta 301763185eb3SVikas Gupta if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { 301863185eb3SVikas Gupta len = strlen(bp->fw_ver_str); 301963185eb3SVikas Gupta snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, 302063185eb3SVikas Gupta "/pkg %s", buf); 302163185eb3SVikas Gupta } 30223ebf6f0aSRob Swindell } 30233ebf6f0aSRob Swindell 3024c0c050c5SMichael Chan static int bnxt_get_eeprom(struct net_device *dev, 3025c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 3026c0c050c5SMichael Chan u8 *data) 3027c0c050c5SMichael Chan { 3028c0c050c5SMichael Chan u32 index; 3029c0c050c5SMichael Chan u32 offset; 3030c0c050c5SMichael Chan 3031c0c050c5SMichael Chan if (eeprom->offset == 0) /* special offset value to get directory */ 3032c0c050c5SMichael Chan return bnxt_get_nvram_directory(dev, eeprom->len, data); 3033c0c050c5SMichael Chan 3034c0c050c5SMichael Chan index = eeprom->offset >> 24; 3035c0c050c5SMichael Chan offset = eeprom->offset & 0xffffff; 3036c0c050c5SMichael Chan 3037c0c050c5SMichael Chan if (index == 0) { 3038c0c050c5SMichael Chan netdev_err(dev, "unsupported index value: %d\n", index); 3039c0c050c5SMichael Chan return -EINVAL; 3040c0c050c5SMichael Chan } 3041c0c050c5SMichael Chan 3042c0c050c5SMichael Chan return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data); 3043c0c050c5SMichael Chan } 3044c0c050c5SMichael Chan 3045c0c050c5SMichael Chan static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) 3046c0c050c5SMichael Chan { 3047bbf33d1dSEdwin Peer struct hwrm_nvm_erase_dir_entry_input *req; 3048c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3049bbf33d1dSEdwin Peer int rc; 3050c0c050c5SMichael Chan 3051bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); 3052bbf33d1dSEdwin Peer if (rc) 3053bbf33d1dSEdwin Peer return rc; 3054bbf33d1dSEdwin Peer 3055bbf33d1dSEdwin Peer req->dir_idx = cpu_to_le16(index); 3056bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3057c0c050c5SMichael Chan } 3058c0c050c5SMichael Chan 3059c0c050c5SMichael Chan static int bnxt_set_eeprom(struct net_device *dev, 3060c0c050c5SMichael Chan struct ethtool_eeprom *eeprom, 3061c0c050c5SMichael Chan u8 *data) 3062c0c050c5SMichael Chan { 3063c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3064c0c050c5SMichael Chan u8 index, dir_op; 3065c0c050c5SMichael Chan u16 type, ext, ordinal, attr; 3066c0c050c5SMichael Chan 3067c0c050c5SMichael Chan if (!BNXT_PF(bp)) { 3068c0c050c5SMichael Chan netdev_err(dev, "NVM write not supported from a virtual function\n"); 3069c0c050c5SMichael Chan return -EINVAL; 3070c0c050c5SMichael Chan } 3071c0c050c5SMichael Chan 3072c0c050c5SMichael Chan type = eeprom->magic >> 16; 3073c0c050c5SMichael Chan 3074c0c050c5SMichael Chan if (type == 0xffff) { /* special value for directory operations */ 3075c0c050c5SMichael Chan index = eeprom->magic & 0xff; 3076c0c050c5SMichael Chan dir_op = eeprom->magic >> 8; 3077c0c050c5SMichael Chan if (index == 0) 3078c0c050c5SMichael Chan return -EINVAL; 3079c0c050c5SMichael Chan switch (dir_op) { 3080c0c050c5SMichael Chan case 0x0e: /* erase */ 3081c0c050c5SMichael Chan if (eeprom->offset != ~eeprom->magic) 3082c0c050c5SMichael Chan return -EINVAL; 3083c0c050c5SMichael Chan return bnxt_erase_nvram_directory(dev, index - 1); 3084c0c050c5SMichael Chan default: 3085c0c050c5SMichael Chan return -EINVAL; 3086c0c050c5SMichael Chan } 3087c0c050c5SMichael Chan } 3088c0c050c5SMichael Chan 3089c0c050c5SMichael Chan /* Create or re-write an NVM item: */ 3090ba425800SJason Yan if (bnxt_dir_type_is_executable(type)) 30915ac67d8bSRob Swindell return -EOPNOTSUPP; 3092c0c050c5SMichael Chan ext = eeprom->magic & 0xffff; 3093c0c050c5SMichael Chan ordinal = eeprom->offset >> 16; 3094c0c050c5SMichael Chan attr = eeprom->offset & 0xffff; 3095c0c050c5SMichael Chan 3096bbf33d1dSEdwin Peer return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data, 3097c0c050c5SMichael Chan eeprom->len); 3098c0c050c5SMichael Chan } 3099c0c050c5SMichael Chan 310072b34f04SMichael Chan static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) 310172b34f04SMichael Chan { 310272b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 310372b34f04SMichael Chan struct ethtool_eee *eee = &bp->eee; 310472b34f04SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 3105a5390690SMichael Chan u32 advertising; 310672b34f04SMichael Chan int rc = 0; 310772b34f04SMichael Chan 3108c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 310975362a3fSMichael Chan return -EOPNOTSUPP; 311072b34f04SMichael Chan 3111b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 311272b34f04SMichael Chan return -EOPNOTSUPP; 311372b34f04SMichael Chan 3114a5390690SMichael Chan mutex_lock(&bp->link_lock); 3115a5390690SMichael Chan advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); 311672b34f04SMichael Chan if (!edata->eee_enabled) 311772b34f04SMichael Chan goto eee_ok; 311872b34f04SMichael Chan 311972b34f04SMichael Chan if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { 312072b34f04SMichael Chan netdev_warn(dev, "EEE requires autoneg\n"); 3121a5390690SMichael Chan rc = -EINVAL; 3122a5390690SMichael Chan goto eee_exit; 312372b34f04SMichael Chan } 312472b34f04SMichael Chan if (edata->tx_lpi_enabled) { 312572b34f04SMichael Chan if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || 312672b34f04SMichael Chan edata->tx_lpi_timer < bp->lpi_tmr_lo)) { 312772b34f04SMichael Chan netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", 312872b34f04SMichael Chan bp->lpi_tmr_lo, bp->lpi_tmr_hi); 3129a5390690SMichael Chan rc = -EINVAL; 3130a5390690SMichael Chan goto eee_exit; 313172b34f04SMichael Chan } else if (!bp->lpi_tmr_hi) { 313272b34f04SMichael Chan edata->tx_lpi_timer = eee->tx_lpi_timer; 313372b34f04SMichael Chan } 313472b34f04SMichael Chan } 313572b34f04SMichael Chan if (!edata->advertised) { 313672b34f04SMichael Chan edata->advertised = advertising & eee->supported; 313772b34f04SMichael Chan } else if (edata->advertised & ~advertising) { 313872b34f04SMichael Chan netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", 313972b34f04SMichael Chan edata->advertised, advertising); 3140a5390690SMichael Chan rc = -EINVAL; 3141a5390690SMichael Chan goto eee_exit; 314272b34f04SMichael Chan } 314372b34f04SMichael Chan 314472b34f04SMichael Chan eee->advertised = edata->advertised; 314572b34f04SMichael Chan eee->tx_lpi_enabled = edata->tx_lpi_enabled; 314672b34f04SMichael Chan eee->tx_lpi_timer = edata->tx_lpi_timer; 314772b34f04SMichael Chan eee_ok: 314872b34f04SMichael Chan eee->eee_enabled = edata->eee_enabled; 314972b34f04SMichael Chan 315072b34f04SMichael Chan if (netif_running(dev)) 315172b34f04SMichael Chan rc = bnxt_hwrm_set_link_setting(bp, false, true); 315272b34f04SMichael Chan 3153a5390690SMichael Chan eee_exit: 3154a5390690SMichael Chan mutex_unlock(&bp->link_lock); 315572b34f04SMichael Chan return rc; 315672b34f04SMichael Chan } 315772b34f04SMichael Chan 315872b34f04SMichael Chan static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) 315972b34f04SMichael Chan { 316072b34f04SMichael Chan struct bnxt *bp = netdev_priv(dev); 316172b34f04SMichael Chan 3162b0d28207SMichael Chan if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) 316372b34f04SMichael Chan return -EOPNOTSUPP; 316472b34f04SMichael Chan 316572b34f04SMichael Chan *edata = bp->eee; 316672b34f04SMichael Chan if (!bp->eee.eee_enabled) { 316772b34f04SMichael Chan /* Preserve tx_lpi_timer so that the last value will be used 316872b34f04SMichael Chan * by default when it is re-enabled. 316972b34f04SMichael Chan */ 317072b34f04SMichael Chan edata->advertised = 0; 317172b34f04SMichael Chan edata->tx_lpi_enabled = 0; 317272b34f04SMichael Chan } 317372b34f04SMichael Chan 317472b34f04SMichael Chan if (!bp->eee.eee_active) 317572b34f04SMichael Chan edata->lp_advertised = 0; 317672b34f04SMichael Chan 317772b34f04SMichael Chan return 0; 317872b34f04SMichael Chan } 317972b34f04SMichael Chan 318042ee18feSAjit Khaparde static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, 31817ef3d390SVikas Gupta u16 page_number, u8 bank, 31827ef3d390SVikas Gupta u16 start_addr, u16 data_length, 31837ef3d390SVikas Gupta u8 *buf) 318442ee18feSAjit Khaparde { 3185bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_output *output; 3186bbf33d1dSEdwin Peer struct hwrm_port_phy_i2c_read_input *req; 318742ee18feSAjit Khaparde int rc, byte_offset = 0; 318842ee18feSAjit Khaparde 3189bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); 3190bbf33d1dSEdwin Peer if (rc) 3191bbf33d1dSEdwin Peer return rc; 3192bbf33d1dSEdwin Peer 3193bbf33d1dSEdwin Peer output = hwrm_req_hold(bp, req); 3194bbf33d1dSEdwin Peer req->i2c_slave_addr = i2c_addr; 3195bbf33d1dSEdwin Peer req->page_number = cpu_to_le16(page_number); 3196bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(bp->pf.port_id); 319742ee18feSAjit Khaparde do { 319842ee18feSAjit Khaparde u16 xfer_size; 319942ee18feSAjit Khaparde 320042ee18feSAjit Khaparde xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); 320142ee18feSAjit Khaparde data_length -= xfer_size; 3202bbf33d1dSEdwin Peer req->page_offset = cpu_to_le16(start_addr + byte_offset); 3203bbf33d1dSEdwin Peer req->data_length = xfer_size; 32047ef3d390SVikas Gupta req->enables = 32057ef3d390SVikas Gupta cpu_to_le32((start_addr + byte_offset ? 32067ef3d390SVikas Gupta PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 32077ef3d390SVikas Gupta 0) | 32087ef3d390SVikas Gupta (bank ? 32097ef3d390SVikas Gupta PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : 32107ef3d390SVikas Gupta 0)); 3211bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 321242ee18feSAjit Khaparde if (!rc) 321342ee18feSAjit Khaparde memcpy(buf + byte_offset, output->data, xfer_size); 321442ee18feSAjit Khaparde byte_offset += xfer_size; 321542ee18feSAjit Khaparde } while (!rc && data_length > 0); 3216bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 321742ee18feSAjit Khaparde 321842ee18feSAjit Khaparde return rc; 321942ee18feSAjit Khaparde } 322042ee18feSAjit Khaparde 322142ee18feSAjit Khaparde static int bnxt_get_module_info(struct net_device *dev, 322242ee18feSAjit Khaparde struct ethtool_modinfo *modinfo) 322342ee18feSAjit Khaparde { 32247328a23cSVasundhara Volam u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; 322542ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 322642ee18feSAjit Khaparde int rc; 322742ee18feSAjit Khaparde 322842ee18feSAjit Khaparde /* No point in going further if phy status indicates 322942ee18feSAjit Khaparde * module is not inserted or if it is powered down or 323042ee18feSAjit Khaparde * if it is of type 10GBase-T 323142ee18feSAjit Khaparde */ 323242ee18feSAjit Khaparde if (bp->link_info.module_status > 323342ee18feSAjit Khaparde PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 323442ee18feSAjit Khaparde return -EOPNOTSUPP; 323542ee18feSAjit Khaparde 323642ee18feSAjit Khaparde /* This feature is not supported in older firmware versions */ 323742ee18feSAjit Khaparde if (bp->hwrm_spec_code < 0x10202) 323842ee18feSAjit Khaparde return -EOPNOTSUPP; 323942ee18feSAjit Khaparde 32407ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, 32417328a23cSVasundhara Volam SFF_DIAG_SUPPORT_OFFSET + 1, 32427328a23cSVasundhara Volam data); 324342ee18feSAjit Khaparde if (!rc) { 32447328a23cSVasundhara Volam u8 module_id = data[0]; 32457328a23cSVasundhara Volam u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; 324642ee18feSAjit Khaparde 324742ee18feSAjit Khaparde switch (module_id) { 324842ee18feSAjit Khaparde case SFF_MODULE_ID_SFP: 324942ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8472; 325042ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 32517328a23cSVasundhara Volam if (!diag_supported) 32527328a23cSVasundhara Volam modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 325342ee18feSAjit Khaparde break; 325442ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP: 325542ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP_PLUS: 325642ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8436; 325742ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 325842ee18feSAjit Khaparde break; 325942ee18feSAjit Khaparde case SFF_MODULE_ID_QSFP28: 326042ee18feSAjit Khaparde modinfo->type = ETH_MODULE_SFF_8636; 326142ee18feSAjit Khaparde modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 326242ee18feSAjit Khaparde break; 326342ee18feSAjit Khaparde default: 326442ee18feSAjit Khaparde rc = -EOPNOTSUPP; 326542ee18feSAjit Khaparde break; 326642ee18feSAjit Khaparde } 326742ee18feSAjit Khaparde } 326842ee18feSAjit Khaparde return rc; 326942ee18feSAjit Khaparde } 327042ee18feSAjit Khaparde 327142ee18feSAjit Khaparde static int bnxt_get_module_eeprom(struct net_device *dev, 327242ee18feSAjit Khaparde struct ethtool_eeprom *eeprom, 327342ee18feSAjit Khaparde u8 *data) 327442ee18feSAjit Khaparde { 327542ee18feSAjit Khaparde struct bnxt *bp = netdev_priv(dev); 327642ee18feSAjit Khaparde u16 start = eeprom->offset, length = eeprom->len; 3277f3ea3119SColin Ian King int rc = 0; 327842ee18feSAjit Khaparde 327942ee18feSAjit Khaparde memset(data, 0, eeprom->len); 328042ee18feSAjit Khaparde 328142ee18feSAjit Khaparde /* Read A0 portion of the EEPROM */ 328242ee18feSAjit Khaparde if (start < ETH_MODULE_SFF_8436_LEN) { 328342ee18feSAjit Khaparde if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) 328442ee18feSAjit Khaparde length = ETH_MODULE_SFF_8436_LEN - start; 32857ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 328642ee18feSAjit Khaparde start, length, data); 328742ee18feSAjit Khaparde if (rc) 328842ee18feSAjit Khaparde return rc; 328942ee18feSAjit Khaparde start += length; 329042ee18feSAjit Khaparde data += length; 329142ee18feSAjit Khaparde length = eeprom->len - length; 329242ee18feSAjit Khaparde } 329342ee18feSAjit Khaparde 329442ee18feSAjit Khaparde /* Read A2 portion of the EEPROM */ 329542ee18feSAjit Khaparde if (length) { 329642ee18feSAjit Khaparde start -= ETH_MODULE_SFF_8436_LEN; 32977ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, 3298dea521a2SChristophe JAILLET start, length, data); 329942ee18feSAjit Khaparde } 330042ee18feSAjit Khaparde return rc; 330142ee18feSAjit Khaparde } 330242ee18feSAjit Khaparde 33037ef3d390SVikas Gupta static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) 33047ef3d390SVikas Gupta { 33057ef3d390SVikas Gupta if (bp->link_info.module_status <= 33067ef3d390SVikas Gupta PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) 33077ef3d390SVikas Gupta return 0; 33087ef3d390SVikas Gupta 33097ef3d390SVikas Gupta switch (bp->link_info.module_status) { 33107ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: 33117ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); 33127ef3d390SVikas Gupta break; 33137ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: 33147ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); 33157ef3d390SVikas Gupta break; 33167ef3d390SVikas Gupta case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: 33177ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault"); 33187ef3d390SVikas Gupta break; 33197ef3d390SVikas Gupta default: 33207ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Unknown error"); 33217ef3d390SVikas Gupta break; 33227ef3d390SVikas Gupta } 33237ef3d390SVikas Gupta return -EINVAL; 33247ef3d390SVikas Gupta } 33257ef3d390SVikas Gupta 33267ef3d390SVikas Gupta static int bnxt_get_module_eeprom_by_page(struct net_device *dev, 33277ef3d390SVikas Gupta const struct ethtool_module_eeprom *page_data, 33287ef3d390SVikas Gupta struct netlink_ext_ack *extack) 33297ef3d390SVikas Gupta { 33307ef3d390SVikas Gupta struct bnxt *bp = netdev_priv(dev); 33317ef3d390SVikas Gupta int rc; 33327ef3d390SVikas Gupta 33337ef3d390SVikas Gupta rc = bnxt_get_module_status(bp, extack); 33347ef3d390SVikas Gupta if (rc) 33357ef3d390SVikas Gupta return rc; 33367ef3d390SVikas Gupta 33377ef3d390SVikas Gupta if (bp->hwrm_spec_code < 0x10202) { 33387ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); 33397ef3d390SVikas Gupta return -EINVAL; 33407ef3d390SVikas Gupta } 33417ef3d390SVikas Gupta 33427ef3d390SVikas Gupta if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { 33437ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); 33447ef3d390SVikas Gupta return -EINVAL; 33457ef3d390SVikas Gupta } 33467ef3d390SVikas Gupta 33477ef3d390SVikas Gupta rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, 33487ef3d390SVikas Gupta page_data->page, page_data->bank, 33497ef3d390SVikas Gupta page_data->offset, 33507ef3d390SVikas Gupta page_data->length, 33517ef3d390SVikas Gupta page_data->data); 33527ef3d390SVikas Gupta if (rc) { 33537ef3d390SVikas Gupta NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); 33547ef3d390SVikas Gupta return rc; 33557ef3d390SVikas Gupta } 33567ef3d390SVikas Gupta return page_data->length; 33577ef3d390SVikas Gupta } 33587ef3d390SVikas Gupta 3359ae8e98a6SDeepak Khungar static int bnxt_nway_reset(struct net_device *dev) 3360ae8e98a6SDeepak Khungar { 3361ae8e98a6SDeepak Khungar int rc = 0; 3362ae8e98a6SDeepak Khungar 3363ae8e98a6SDeepak Khungar struct bnxt *bp = netdev_priv(dev); 3364ae8e98a6SDeepak Khungar struct bnxt_link_info *link_info = &bp->link_info; 3365ae8e98a6SDeepak Khungar 3366c7e457f4SMichael Chan if (!BNXT_PHY_CFG_ABLE(bp)) 3367ae8e98a6SDeepak Khungar return -EOPNOTSUPP; 3368ae8e98a6SDeepak Khungar 3369ae8e98a6SDeepak Khungar if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) 3370ae8e98a6SDeepak Khungar return -EINVAL; 3371ae8e98a6SDeepak Khungar 3372ae8e98a6SDeepak Khungar if (netif_running(dev)) 3373ae8e98a6SDeepak Khungar rc = bnxt_hwrm_set_link_setting(bp, true, false); 3374ae8e98a6SDeepak Khungar 3375ae8e98a6SDeepak Khungar return rc; 3376ae8e98a6SDeepak Khungar } 3377ae8e98a6SDeepak Khungar 33785ad2cbeeSMichael Chan static int bnxt_set_phys_id(struct net_device *dev, 33795ad2cbeeSMichael Chan enum ethtool_phys_id_state state) 33805ad2cbeeSMichael Chan { 3381bbf33d1dSEdwin Peer struct hwrm_port_led_cfg_input *req; 33825ad2cbeeSMichael Chan struct bnxt *bp = netdev_priv(dev); 33835ad2cbeeSMichael Chan struct bnxt_pf_info *pf = &bp->pf; 33845ad2cbeeSMichael Chan struct bnxt_led_cfg *led_cfg; 33855ad2cbeeSMichael Chan u8 led_state; 33865ad2cbeeSMichael Chan __le16 duration; 3387bbf33d1dSEdwin Peer int rc, i; 33885ad2cbeeSMichael Chan 33895ad2cbeeSMichael Chan if (!bp->num_leds || BNXT_VF(bp)) 33905ad2cbeeSMichael Chan return -EOPNOTSUPP; 33915ad2cbeeSMichael Chan 33925ad2cbeeSMichael Chan if (state == ETHTOOL_ID_ACTIVE) { 33935ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; 33945ad2cbeeSMichael Chan duration = cpu_to_le16(500); 33955ad2cbeeSMichael Chan } else if (state == ETHTOOL_ID_INACTIVE) { 33965ad2cbeeSMichael Chan led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; 33975ad2cbeeSMichael Chan duration = cpu_to_le16(0); 33985ad2cbeeSMichael Chan } else { 33995ad2cbeeSMichael Chan return -EINVAL; 34005ad2cbeeSMichael Chan } 3401bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); 3402bbf33d1dSEdwin Peer if (rc) 3403bbf33d1dSEdwin Peer return rc; 3404bbf33d1dSEdwin Peer 3405bbf33d1dSEdwin Peer req->port_id = cpu_to_le16(pf->port_id); 3406bbf33d1dSEdwin Peer req->num_leds = bp->num_leds; 3407bbf33d1dSEdwin Peer led_cfg = (struct bnxt_led_cfg *)&req->led0_id; 34085ad2cbeeSMichael Chan for (i = 0; i < bp->num_leds; i++, led_cfg++) { 3409bbf33d1dSEdwin Peer req->enables |= BNXT_LED_DFLT_ENABLES(i); 34105ad2cbeeSMichael Chan led_cfg->led_id = bp->leds[i].led_id; 34115ad2cbeeSMichael Chan led_cfg->led_state = led_state; 34125ad2cbeeSMichael Chan led_cfg->led_blink_on = duration; 34135ad2cbeeSMichael Chan led_cfg->led_blink_off = duration; 34145ad2cbeeSMichael Chan led_cfg->led_group_id = bp->leds[i].led_group_id; 34155ad2cbeeSMichael Chan } 3416bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 34175ad2cbeeSMichael Chan } 34185ad2cbeeSMichael Chan 341967fea463SMichael Chan static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) 342067fea463SMichael Chan { 3421bbf33d1dSEdwin Peer struct hwrm_selftest_irq_input *req; 3422bbf33d1dSEdwin Peer int rc; 342367fea463SMichael Chan 3424bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); 3425bbf33d1dSEdwin Peer if (rc) 3426bbf33d1dSEdwin Peer return rc; 3427bbf33d1dSEdwin Peer 3428bbf33d1dSEdwin Peer req->cmpl_ring = cpu_to_le16(cmpl_ring); 3429bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 343067fea463SMichael Chan } 343167fea463SMichael Chan 343267fea463SMichael Chan static int bnxt_test_irq(struct bnxt *bp) 343367fea463SMichael Chan { 343467fea463SMichael Chan int i; 343567fea463SMichael Chan 343667fea463SMichael Chan for (i = 0; i < bp->cp_nr_rings; i++) { 343767fea463SMichael Chan u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; 343867fea463SMichael Chan int rc; 343967fea463SMichael Chan 344067fea463SMichael Chan rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); 344167fea463SMichael Chan if (rc) 344267fea463SMichael Chan return rc; 344367fea463SMichael Chan } 344467fea463SMichael Chan return 0; 344567fea463SMichael Chan } 344667fea463SMichael Chan 3447f7dc1ea6SMichael Chan static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) 3448f7dc1ea6SMichael Chan { 3449bbf33d1dSEdwin Peer struct hwrm_port_mac_cfg_input *req; 3450bbf33d1dSEdwin Peer int rc; 3451f7dc1ea6SMichael Chan 3452bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); 3453bbf33d1dSEdwin Peer if (rc) 3454bbf33d1dSEdwin Peer return rc; 3455f7dc1ea6SMichael Chan 3456bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); 3457f7dc1ea6SMichael Chan if (enable) 3458bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; 3459f7dc1ea6SMichael Chan else 3460bbf33d1dSEdwin Peer req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; 3461bbf33d1dSEdwin Peer return hwrm_req_send(bp, req); 3462f7dc1ea6SMichael Chan } 3463f7dc1ea6SMichael Chan 346456d37462SVasundhara Volam static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) 346556d37462SVasundhara Volam { 3466bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_output *resp; 3467bbf33d1dSEdwin Peer struct hwrm_port_phy_qcaps_input *req; 346856d37462SVasundhara Volam int rc; 346956d37462SVasundhara Volam 3470bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); 3471bbf33d1dSEdwin Peer if (rc) 3472bbf33d1dSEdwin Peer return rc; 3473bbf33d1dSEdwin Peer 3474bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3475bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 347656d37462SVasundhara Volam if (!rc) 347756d37462SVasundhara Volam *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); 347856d37462SVasundhara Volam 3479bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 348056d37462SVasundhara Volam return rc; 348156d37462SVasundhara Volam } 348256d37462SVasundhara Volam 348391725d89SMichael Chan static int bnxt_disable_an_for_lpbk(struct bnxt *bp, 348491725d89SMichael Chan struct hwrm_port_phy_cfg_input *req) 348591725d89SMichael Chan { 348691725d89SMichael Chan struct bnxt_link_info *link_info = &bp->link_info; 348756d37462SVasundhara Volam u16 fw_advertising; 348891725d89SMichael Chan u16 fw_speed; 348991725d89SMichael Chan int rc; 349091725d89SMichael Chan 34918a60efd1SMichael Chan if (!link_info->autoneg || 3492b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) 349391725d89SMichael Chan return 0; 349491725d89SMichael Chan 349556d37462SVasundhara Volam rc = bnxt_query_force_speeds(bp, &fw_advertising); 349656d37462SVasundhara Volam if (rc) 349756d37462SVasundhara Volam return rc; 349856d37462SVasundhara Volam 349991725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; 35000f5a4841SEdwin Peer if (BNXT_LINK_IS_UP(bp)) 350191725d89SMichael Chan fw_speed = bp->link_info.link_speed; 350291725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) 350391725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; 350491725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) 350591725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; 350691725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) 350791725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; 350891725d89SMichael Chan else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) 350991725d89SMichael Chan fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; 351091725d89SMichael Chan 351191725d89SMichael Chan req->force_link_speed = cpu_to_le16(fw_speed); 351291725d89SMichael Chan req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | 351391725d89SMichael Chan PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); 3514bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 351591725d89SMichael Chan req->flags = 0; 351691725d89SMichael Chan req->force_link_speed = cpu_to_le16(0); 351791725d89SMichael Chan return rc; 351891725d89SMichael Chan } 351991725d89SMichael Chan 352055fd0cf3SMichael Chan static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) 352191725d89SMichael Chan { 3522bbf33d1dSEdwin Peer struct hwrm_port_phy_cfg_input *req; 3523bbf33d1dSEdwin Peer int rc; 352491725d89SMichael Chan 3525bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); 3526bbf33d1dSEdwin Peer if (rc) 3527bbf33d1dSEdwin Peer return rc; 3528bbf33d1dSEdwin Peer 3529bbf33d1dSEdwin Peer /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ 3530bbf33d1dSEdwin Peer hwrm_req_hold(bp, req); 353191725d89SMichael Chan 353291725d89SMichael Chan if (enable) { 3533bbf33d1dSEdwin Peer bnxt_disable_an_for_lpbk(bp, req); 353455fd0cf3SMichael Chan if (ext) 3535bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; 353655fd0cf3SMichael Chan else 3537bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; 353891725d89SMichael Chan } else { 3539bbf33d1dSEdwin Peer req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; 354091725d89SMichael Chan } 3541bbf33d1dSEdwin Peer req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); 3542bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3543bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3544bbf33d1dSEdwin Peer return rc; 354591725d89SMichael Chan } 354691725d89SMichael Chan 3547e44758b7SMichael Chan static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3548f7dc1ea6SMichael Chan u32 raw_cons, int pkt_size) 3549f7dc1ea6SMichael Chan { 3550e44758b7SMichael Chan struct bnxt_napi *bnapi = cpr->bnapi; 3551e44758b7SMichael Chan struct bnxt_rx_ring_info *rxr; 3552f7dc1ea6SMichael Chan struct bnxt_sw_rx_bd *rx_buf; 3553f7dc1ea6SMichael Chan struct rx_cmp *rxcmp; 3554f7dc1ea6SMichael Chan u16 cp_cons, cons; 3555f7dc1ea6SMichael Chan u8 *data; 3556f7dc1ea6SMichael Chan u32 len; 3557f7dc1ea6SMichael Chan int i; 3558f7dc1ea6SMichael Chan 3559e44758b7SMichael Chan rxr = bnapi->rx_ring; 3560f7dc1ea6SMichael Chan cp_cons = RING_CMP(raw_cons); 3561f7dc1ea6SMichael Chan rxcmp = (struct rx_cmp *) 3562f7dc1ea6SMichael Chan &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; 3563f7dc1ea6SMichael Chan cons = rxcmp->rx_cmp_opaque; 3564f7dc1ea6SMichael Chan rx_buf = &rxr->rx_buf_ring[cons]; 3565f7dc1ea6SMichael Chan data = rx_buf->data_ptr; 3566f7dc1ea6SMichael Chan len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; 3567f7dc1ea6SMichael Chan if (len != pkt_size) 3568f7dc1ea6SMichael Chan return -EIO; 3569f7dc1ea6SMichael Chan i = ETH_ALEN; 3570f7dc1ea6SMichael Chan if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) 3571f7dc1ea6SMichael Chan return -EIO; 3572f7dc1ea6SMichael Chan i += ETH_ALEN; 3573f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) { 3574f7dc1ea6SMichael Chan if (data[i] != (u8)(i & 0xff)) 3575f7dc1ea6SMichael Chan return -EIO; 3576f7dc1ea6SMichael Chan } 3577f7dc1ea6SMichael Chan return 0; 3578f7dc1ea6SMichael Chan } 3579f7dc1ea6SMichael Chan 3580e44758b7SMichael Chan static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, 3581e44758b7SMichael Chan int pkt_size) 3582f7dc1ea6SMichael Chan { 3583f7dc1ea6SMichael Chan struct tx_cmp *txcmp; 3584f7dc1ea6SMichael Chan int rc = -EIO; 3585f7dc1ea6SMichael Chan u32 raw_cons; 3586f7dc1ea6SMichael Chan u32 cons; 3587f7dc1ea6SMichael Chan int i; 3588f7dc1ea6SMichael Chan 3589f7dc1ea6SMichael Chan raw_cons = cpr->cp_raw_cons; 3590f7dc1ea6SMichael Chan for (i = 0; i < 200; i++) { 3591f7dc1ea6SMichael Chan cons = RING_CMP(raw_cons); 3592f7dc1ea6SMichael Chan txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; 3593f7dc1ea6SMichael Chan 3594f7dc1ea6SMichael Chan if (!TX_CMP_VALID(txcmp, raw_cons)) { 3595f7dc1ea6SMichael Chan udelay(5); 3596f7dc1ea6SMichael Chan continue; 3597f7dc1ea6SMichael Chan } 3598f7dc1ea6SMichael Chan 3599f7dc1ea6SMichael Chan /* The valid test of the entry must be done first before 3600f7dc1ea6SMichael Chan * reading any further. 3601f7dc1ea6SMichael Chan */ 3602f7dc1ea6SMichael Chan dma_rmb(); 3603f7dc1ea6SMichael Chan if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { 3604e44758b7SMichael Chan rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); 3605f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3606f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3607f7dc1ea6SMichael Chan break; 3608f7dc1ea6SMichael Chan } 3609f7dc1ea6SMichael Chan raw_cons = NEXT_RAW_CMP(raw_cons); 3610f7dc1ea6SMichael Chan } 3611f7dc1ea6SMichael Chan cpr->cp_raw_cons = raw_cons; 3612f7dc1ea6SMichael Chan return rc; 3613f7dc1ea6SMichael Chan } 3614f7dc1ea6SMichael Chan 3615f7dc1ea6SMichael Chan static int bnxt_run_loopback(struct bnxt *bp) 3616f7dc1ea6SMichael Chan { 3617f7dc1ea6SMichael Chan struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; 361884404d5fSMichael Chan struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; 3619e44758b7SMichael Chan struct bnxt_cp_ring_info *cpr; 3620f7dc1ea6SMichael Chan int pkt_size, i = 0; 3621f7dc1ea6SMichael Chan struct sk_buff *skb; 3622f7dc1ea6SMichael Chan dma_addr_t map; 3623f7dc1ea6SMichael Chan u8 *data; 3624f7dc1ea6SMichael Chan int rc; 3625f7dc1ea6SMichael Chan 362684404d5fSMichael Chan cpr = &rxr->bnapi->cp_ring; 362784404d5fSMichael Chan if (bp->flags & BNXT_FLAG_CHIP_P5) 362884404d5fSMichael Chan cpr = cpr->cp_ring_arr[BNXT_RX_HDL]; 3629f7dc1ea6SMichael Chan pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); 3630f7dc1ea6SMichael Chan skb = netdev_alloc_skb(bp->dev, pkt_size); 3631f7dc1ea6SMichael Chan if (!skb) 3632f7dc1ea6SMichael Chan return -ENOMEM; 3633f7dc1ea6SMichael Chan data = skb_put(skb, pkt_size); 3634cfcab3b3SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3635f7dc1ea6SMichael Chan i += ETH_ALEN; 3636f7dc1ea6SMichael Chan ether_addr_copy(&data[i], bp->dev->dev_addr); 3637f7dc1ea6SMichael Chan i += ETH_ALEN; 3638f7dc1ea6SMichael Chan for ( ; i < pkt_size; i++) 3639f7dc1ea6SMichael Chan data[i] = (u8)(i & 0xff); 3640f7dc1ea6SMichael Chan 3641f7dc1ea6SMichael Chan map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 3642df70303dSChristophe JAILLET DMA_TO_DEVICE); 3643f7dc1ea6SMichael Chan if (dma_mapping_error(&bp->pdev->dev, map)) { 3644f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3645f7dc1ea6SMichael Chan return -EIO; 3646f7dc1ea6SMichael Chan } 3647a7559bc8SAndy Gospodarek bnxt_xmit_bd(bp, txr, map, pkt_size, NULL); 3648f7dc1ea6SMichael Chan 3649f7dc1ea6SMichael Chan /* Sync BD data before updating doorbell */ 3650f7dc1ea6SMichael Chan wmb(); 3651f7dc1ea6SMichael Chan 3652697197e5SMichael Chan bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); 3653e44758b7SMichael Chan rc = bnxt_poll_loopback(bp, cpr, pkt_size); 3654f7dc1ea6SMichael Chan 3655df70303dSChristophe JAILLET dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); 3656f7dc1ea6SMichael Chan dev_kfree_skb(skb); 3657f7dc1ea6SMichael Chan return rc; 3658f7dc1ea6SMichael Chan } 3659f7dc1ea6SMichael Chan 3660eb513658SMichael Chan static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) 3661eb513658SMichael Chan { 3662bbf33d1dSEdwin Peer struct hwrm_selftest_exec_output *resp; 3663bbf33d1dSEdwin Peer struct hwrm_selftest_exec_input *req; 3664eb513658SMichael Chan int rc; 3665eb513658SMichael Chan 3666bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); 3667bbf33d1dSEdwin Peer if (rc) 3668bbf33d1dSEdwin Peer return rc; 3669bbf33d1dSEdwin Peer 3670bbf33d1dSEdwin Peer hwrm_req_timeout(bp, req, bp->test_info->timeout); 3671bbf33d1dSEdwin Peer req->flags = test_mask; 3672bbf33d1dSEdwin Peer 3673bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3674bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req); 3675eb513658SMichael Chan *test_results = resp->test_success; 3676bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3677eb513658SMichael Chan return rc; 3678eb513658SMichael Chan } 3679eb513658SMichael Chan 368055fd0cf3SMichael Chan #define BNXT_DRV_TESTS 4 3681f7dc1ea6SMichael Chan #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) 368291725d89SMichael Chan #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) 368355fd0cf3SMichael Chan #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) 368455fd0cf3SMichael Chan #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) 3685eb513658SMichael Chan 3686eb513658SMichael Chan static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, 3687eb513658SMichael Chan u64 *buf) 3688eb513658SMichael Chan { 3689eb513658SMichael Chan struct bnxt *bp = netdev_priv(dev); 369055fd0cf3SMichael Chan bool do_ext_lpbk = false; 3691eb513658SMichael Chan bool offline = false; 3692eb513658SMichael Chan u8 test_results = 0; 3693eb513658SMichael Chan u8 test_mask = 0; 3694d27e2ca1SMichael Chan int rc = 0, i; 3695eb513658SMichael Chan 36966896cb35SVasundhara Volam if (!bp->num_tests || !BNXT_PF(bp)) 3697eb513658SMichael Chan return; 3698eb513658SMichael Chan memset(buf, 0, sizeof(u64) * bp->num_tests); 3699eb513658SMichael Chan if (!netif_running(dev)) { 3700eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3701eb513658SMichael Chan return; 3702eb513658SMichael Chan } 3703eb513658SMichael Chan 370455fd0cf3SMichael Chan if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && 3705b0d28207SMichael Chan (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) 370655fd0cf3SMichael Chan do_ext_lpbk = true; 370755fd0cf3SMichael Chan 3708eb513658SMichael Chan if (etest->flags & ETH_TEST_FL_OFFLINE) { 37096896cb35SVasundhara Volam if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { 3710eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 37116896cb35SVasundhara Volam netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n"); 3712eb513658SMichael Chan return; 3713eb513658SMichael Chan } 3714eb513658SMichael Chan offline = true; 3715eb513658SMichael Chan } 3716eb513658SMichael Chan 3717eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3718eb513658SMichael Chan u8 bit_val = 1 << i; 3719eb513658SMichael Chan 3720eb513658SMichael Chan if (!(bp->test_info->offline_mask & bit_val)) 3721eb513658SMichael Chan test_mask |= bit_val; 3722eb513658SMichael Chan else if (offline) 3723eb513658SMichael Chan test_mask |= bit_val; 3724eb513658SMichael Chan } 3725eb513658SMichael Chan if (!offline) { 3726eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3727eb513658SMichael Chan } else { 37286758f937SMichael Chan bnxt_ulp_stop(bp); 37296758f937SMichael Chan rc = bnxt_close_nic(bp, true, false); 37306758f937SMichael Chan if (rc) { 37316758f937SMichael Chan bnxt_ulp_start(bp, rc); 3732eb513658SMichael Chan return; 37336758f937SMichael Chan } 3734eb513658SMichael Chan bnxt_run_fw_tests(bp, test_mask, &test_results); 3735f7dc1ea6SMichael Chan 3736f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 1; 3737f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, true); 3738f7dc1ea6SMichael Chan msleep(250); 3739f7dc1ea6SMichael Chan rc = bnxt_half_open_nic(bp); 3740f7dc1ea6SMichael Chan if (rc) { 3741f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 3742f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 37436758f937SMichael Chan bnxt_ulp_start(bp, rc); 3744f7dc1ea6SMichael Chan return; 3745f7dc1ea6SMichael Chan } 3746f7dc1ea6SMichael Chan if (bnxt_run_loopback(bp)) 3747f7dc1ea6SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3748f7dc1ea6SMichael Chan else 3749f7dc1ea6SMichael Chan buf[BNXT_MACLPBK_TEST_IDX] = 0; 3750f7dc1ea6SMichael Chan 3751f7dc1ea6SMichael Chan bnxt_hwrm_mac_loopback(bp, false); 375255fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, false); 375391725d89SMichael Chan msleep(1000); 375491725d89SMichael Chan if (bnxt_run_loopback(bp)) { 375591725d89SMichael Chan buf[BNXT_PHYLPBK_TEST_IDX] = 1; 375691725d89SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 375791725d89SMichael Chan } 375855fd0cf3SMichael Chan if (do_ext_lpbk) { 375955fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 376055fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, true, true); 376155fd0cf3SMichael Chan msleep(1000); 376255fd0cf3SMichael Chan if (bnxt_run_loopback(bp)) { 376355fd0cf3SMichael Chan buf[BNXT_EXTLPBK_TEST_IDX] = 1; 376455fd0cf3SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 376555fd0cf3SMichael Chan } 376655fd0cf3SMichael Chan } 376755fd0cf3SMichael Chan bnxt_hwrm_phy_loopback(bp, false, false); 376891725d89SMichael Chan bnxt_half_close_nic(bp); 37696758f937SMichael Chan rc = bnxt_open_nic(bp, true, true); 37706758f937SMichael Chan bnxt_ulp_start(bp, rc); 3771eb513658SMichael Chan } 3772d27e2ca1SMichael Chan if (rc || bnxt_test_irq(bp)) { 377367fea463SMichael Chan buf[BNXT_IRQ_TEST_IDX] = 1; 377467fea463SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 377567fea463SMichael Chan } 3776eb513658SMichael Chan for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { 3777eb513658SMichael Chan u8 bit_val = 1 << i; 3778eb513658SMichael Chan 3779eb513658SMichael Chan if ((test_mask & bit_val) && !(test_results & bit_val)) { 3780eb513658SMichael Chan buf[i] = 1; 3781eb513658SMichael Chan etest->flags |= ETH_TEST_FL_FAILED; 3782eb513658SMichael Chan } 3783eb513658SMichael Chan } 3784eb513658SMichael Chan } 3785eb513658SMichael Chan 378649f7972fSVasundhara Volam static int bnxt_reset(struct net_device *dev, u32 *flags) 378749f7972fSVasundhara Volam { 378849f7972fSVasundhara Volam struct bnxt *bp = netdev_priv(dev); 37898cec0940SEdwin Peer bool reload = false; 37907a13240eSEdwin Peer u32 req = *flags; 37917a13240eSEdwin Peer 37927a13240eSEdwin Peer if (!req) 37937a13240eSEdwin Peer return -EINVAL; 379449f7972fSVasundhara Volam 379549f7972fSVasundhara Volam if (!BNXT_PF(bp)) { 379649f7972fSVasundhara Volam netdev_err(dev, "Reset is not supported from a VF\n"); 379749f7972fSVasundhara Volam return -EOPNOTSUPP; 379849f7972fSVasundhara Volam } 379949f7972fSVasundhara Volam 38000a3f4e4fSVasundhara Volam if (pci_vfs_assigned(bp->pdev) && 38010a3f4e4fSVasundhara Volam !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { 380249f7972fSVasundhara Volam netdev_err(dev, 380349f7972fSVasundhara Volam "Reset not allowed when VFs are assigned to VMs\n"); 380449f7972fSVasundhara Volam return -EBUSY; 380549f7972fSVasundhara Volam } 380649f7972fSVasundhara Volam 38077a13240eSEdwin Peer if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { 380849f7972fSVasundhara Volam /* This feature is not supported in older firmware versions */ 38097a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 38107a13240eSEdwin Peer if (!bnxt_firmware_reset_chip(dev)) { 38117a13240eSEdwin Peer netdev_info(dev, "Firmware reset request successful.\n"); 38120a3f4e4fSVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) 38138cec0940SEdwin Peer reload = true; 38147a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_CHIP; 38152373d8d6SScott Branden } 38167a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_CHIP) { 38177a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 38187a13240eSEdwin Peer } 38197a13240eSEdwin Peer } 38207a13240eSEdwin Peer 38217a13240eSEdwin Peer if (req & BNXT_FW_RESET_AP) { 38226502ad59SScott Branden /* This feature is not supported in older firmware versions */ 38237a13240eSEdwin Peer if (bp->hwrm_spec_code >= 0x10803) { 38247a13240eSEdwin Peer if (!bnxt_firmware_reset_ap(dev)) { 38257a13240eSEdwin Peer netdev_info(dev, "Reset application processor successful.\n"); 38268cec0940SEdwin Peer reload = true; 38277a13240eSEdwin Peer *flags &= ~BNXT_FW_RESET_AP; 38282373d8d6SScott Branden } 38297a13240eSEdwin Peer } else if (req == BNXT_FW_RESET_AP) { 38307a13240eSEdwin Peer return -EOPNOTSUPP; /* only request, fail hard */ 38317a13240eSEdwin Peer } 383249f7972fSVasundhara Volam } 383349f7972fSVasundhara Volam 38348cec0940SEdwin Peer if (reload) 38358cec0940SEdwin Peer netdev_info(dev, "Reload driver to complete reset\n"); 38368cec0940SEdwin Peer 38377a13240eSEdwin Peer return 0; 383849f7972fSVasundhara Volam } 383949f7972fSVasundhara Volam 38400b0eacf3SVasundhara Volam static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) 38410b0eacf3SVasundhara Volam { 38420b0eacf3SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38430b0eacf3SVasundhara Volam 38440b0eacf3SVasundhara Volam if (dump->flag > BNXT_DUMP_CRASH) { 38450b0eacf3SVasundhara Volam netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); 38460b0eacf3SVasundhara Volam return -EINVAL; 38470b0eacf3SVasundhara Volam } 38480b0eacf3SVasundhara Volam 38490b0eacf3SVasundhara Volam if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { 38500b0eacf3SVasundhara Volam netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); 38510b0eacf3SVasundhara Volam return -EOPNOTSUPP; 38520b0eacf3SVasundhara Volam } 38530b0eacf3SVasundhara Volam 38540b0eacf3SVasundhara Volam bp->dump_flag = dump->flag; 38550b0eacf3SVasundhara Volam return 0; 38560b0eacf3SVasundhara Volam } 38570b0eacf3SVasundhara Volam 38586c5657d0SVasundhara Volam static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) 38596c5657d0SVasundhara Volam { 38606c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38616c5657d0SVasundhara Volam 38626c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 38636c5657d0SVasundhara Volam return -EOPNOTSUPP; 38646c5657d0SVasundhara Volam 38656c5657d0SVasundhara Volam dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | 38666c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_min_8b << 16 | 38676c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_bld_8b << 8 | 38686c5657d0SVasundhara Volam bp->ver_resp.hwrm_fw_rsvd_8b; 38696c5657d0SVasundhara Volam 38700b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 38719a575c8cSEdwin Peer dump->len = bnxt_get_coredump_length(bp, bp->dump_flag); 38720b0eacf3SVasundhara Volam return 0; 38736c5657d0SVasundhara Volam } 38746c5657d0SVasundhara Volam 38756c5657d0SVasundhara Volam static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, 38766c5657d0SVasundhara Volam void *buf) 38776c5657d0SVasundhara Volam { 38786c5657d0SVasundhara Volam struct bnxt *bp = netdev_priv(dev); 38796c5657d0SVasundhara Volam 38806c5657d0SVasundhara Volam if (bp->hwrm_spec_code < 0x10801) 38816c5657d0SVasundhara Volam return -EOPNOTSUPP; 38826c5657d0SVasundhara Volam 38836c5657d0SVasundhara Volam memset(buf, 0, dump->len); 38846c5657d0SVasundhara Volam 38850b0eacf3SVasundhara Volam dump->flag = bp->dump_flag; 38869a575c8cSEdwin Peer return bnxt_get_coredump(bp, dump->flag, buf, &dump->len); 38870b0eacf3SVasundhara Volam } 38880b0eacf3SVasundhara Volam 3889118612d5SMichael Chan static int bnxt_get_ts_info(struct net_device *dev, 3890118612d5SMichael Chan struct ethtool_ts_info *info) 3891118612d5SMichael Chan { 3892118612d5SMichael Chan struct bnxt *bp = netdev_priv(dev); 3893118612d5SMichael Chan struct bnxt_ptp_cfg *ptp; 3894118612d5SMichael Chan 3895118612d5SMichael Chan ptp = bp->ptp_cfg; 3896118612d5SMichael Chan info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 3897118612d5SMichael Chan SOF_TIMESTAMPING_RX_SOFTWARE | 3898118612d5SMichael Chan SOF_TIMESTAMPING_SOFTWARE; 3899118612d5SMichael Chan 3900118612d5SMichael Chan info->phc_index = -1; 3901118612d5SMichael Chan if (!ptp) 3902118612d5SMichael Chan return 0; 3903118612d5SMichael Chan 3904118612d5SMichael Chan info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | 3905118612d5SMichael Chan SOF_TIMESTAMPING_RX_HARDWARE | 3906118612d5SMichael Chan SOF_TIMESTAMPING_RAW_HARDWARE; 3907118612d5SMichael Chan if (ptp->ptp_clock) 3908118612d5SMichael Chan info->phc_index = ptp_clock_index(ptp->ptp_clock); 3909118612d5SMichael Chan 3910118612d5SMichael Chan info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); 3911118612d5SMichael Chan 3912118612d5SMichael Chan info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 3913118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | 3914118612d5SMichael Chan (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 391566ed81dcSPavan Chebbi 391666ed81dcSPavan Chebbi if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) 391766ed81dcSPavan Chebbi info->rx_filters |= (1 << HWTSTAMP_FILTER_ALL); 3918118612d5SMichael Chan return 0; 3919118612d5SMichael Chan } 3920118612d5SMichael Chan 3921eb513658SMichael Chan void bnxt_ethtool_init(struct bnxt *bp) 3922eb513658SMichael Chan { 3923bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_output *resp; 3924bbf33d1dSEdwin Peer struct hwrm_selftest_qlist_input *req; 3925eb513658SMichael Chan struct bnxt_test_info *test_info; 3926431aa1ebSMichael Chan struct net_device *dev = bp->dev; 3927eb513658SMichael Chan int i, rc; 3928eb513658SMichael Chan 3929691aa620SVasundhara Volam if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) 3930a60faa60SVasundhara Volam bnxt_get_pkgver(dev); 3931431aa1ebSMichael Chan 3932ba642ab7SMichael Chan bp->num_tests = 0; 39336896cb35SVasundhara Volam if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) 3934eb513658SMichael Chan return; 3935eb513658SMichael Chan 3936bbf33d1dSEdwin Peer test_info = bp->test_info; 3937bbf33d1dSEdwin Peer if (!test_info) { 3938bbf33d1dSEdwin Peer test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); 3939bbf33d1dSEdwin Peer if (!test_info) 3940bbf33d1dSEdwin Peer return; 3941bbf33d1dSEdwin Peer bp->test_info = test_info; 3942bbf33d1dSEdwin Peer } 3943bbf33d1dSEdwin Peer 3944bbf33d1dSEdwin Peer if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) 3945bbf33d1dSEdwin Peer return; 3946bbf33d1dSEdwin Peer 3947bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req); 3948bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req); 3949eb513658SMichael Chan if (rc) 3950eb513658SMichael Chan goto ethtool_init_exit; 3951eb513658SMichael Chan 3952eb513658SMichael Chan bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; 3953eb513658SMichael Chan if (bp->num_tests > BNXT_MAX_TEST) 3954eb513658SMichael Chan bp->num_tests = BNXT_MAX_TEST; 3955eb513658SMichael Chan 3956eb513658SMichael Chan test_info->offline_mask = resp->offline_tests; 3957eb513658SMichael Chan test_info->timeout = le16_to_cpu(resp->test_timeout); 3958eb513658SMichael Chan if (!test_info->timeout) 3959eb513658SMichael Chan test_info->timeout = HWRM_CMD_TIMEOUT; 3960eb513658SMichael Chan for (i = 0; i < bp->num_tests; i++) { 3961eb513658SMichael Chan char *str = test_info->string[i]; 3962eb513658SMichael Chan char *fw_str = resp->test0_name + i * 32; 3963eb513658SMichael Chan 3964f7dc1ea6SMichael Chan if (i == BNXT_MACLPBK_TEST_IDX) { 3965f7dc1ea6SMichael Chan strcpy(str, "Mac loopback test (offline)"); 396691725d89SMichael Chan } else if (i == BNXT_PHYLPBK_TEST_IDX) { 396791725d89SMichael Chan strcpy(str, "Phy loopback test (offline)"); 396855fd0cf3SMichael Chan } else if (i == BNXT_EXTLPBK_TEST_IDX) { 396955fd0cf3SMichael Chan strcpy(str, "Ext loopback test (offline)"); 397067fea463SMichael Chan } else if (i == BNXT_IRQ_TEST_IDX) { 397167fea463SMichael Chan strcpy(str, "Interrupt_test (offline)"); 3972f7dc1ea6SMichael Chan } else { 3973f029c781SWolfram Sang strscpy(str, fw_str, ETH_GSTRING_LEN); 3974eb513658SMichael Chan strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); 3975eb513658SMichael Chan if (test_info->offline_mask & (1 << i)) 3976eb513658SMichael Chan strncat(str, " (offline)", 3977eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3978eb513658SMichael Chan else 3979eb513658SMichael Chan strncat(str, " (online)", 3980eb513658SMichael Chan ETH_GSTRING_LEN - strlen(str)); 3981eb513658SMichael Chan } 3982f7dc1ea6SMichael Chan } 3983eb513658SMichael Chan 3984eb513658SMichael Chan ethtool_init_exit: 3985bbf33d1dSEdwin Peer hwrm_req_drop(bp, req); 3986eb513658SMichael Chan } 3987eb513658SMichael Chan 3988782bc00aSJakub Kicinski static void bnxt_get_eth_phy_stats(struct net_device *dev, 3989782bc00aSJakub Kicinski struct ethtool_eth_phy_stats *phy_stats) 3990782bc00aSJakub Kicinski { 3991782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 3992782bc00aSJakub Kicinski u64 *rx; 3993782bc00aSJakub Kicinski 3994782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) 3995782bc00aSJakub Kicinski return; 3996782bc00aSJakub Kicinski 3997782bc00aSJakub Kicinski rx = bp->rx_port_stats_ext.sw_stats; 3998782bc00aSJakub Kicinski phy_stats->SymbolErrorDuringCarrier = 3999782bc00aSJakub Kicinski *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); 4000782bc00aSJakub Kicinski } 4001782bc00aSJakub Kicinski 4002782bc00aSJakub Kicinski static void bnxt_get_eth_mac_stats(struct net_device *dev, 4003782bc00aSJakub Kicinski struct ethtool_eth_mac_stats *mac_stats) 4004782bc00aSJakub Kicinski { 4005782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4006782bc00aSJakub Kicinski u64 *rx, *tx; 4007782bc00aSJakub Kicinski 4008782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4009782bc00aSJakub Kicinski return; 4010782bc00aSJakub Kicinski 4011782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4012782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 4013782bc00aSJakub Kicinski 4014782bc00aSJakub Kicinski mac_stats->FramesReceivedOK = 4015782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); 4016782bc00aSJakub Kicinski mac_stats->FramesTransmittedOK = 4017782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); 401837434782SJakub Kicinski mac_stats->FrameCheckSequenceErrors = 401937434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); 402037434782SJakub Kicinski mac_stats->AlignmentErrors = 402137434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); 402237434782SJakub Kicinski mac_stats->OutOfRangeLengthField = 402337434782SJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); 4024782bc00aSJakub Kicinski } 4025782bc00aSJakub Kicinski 4026782bc00aSJakub Kicinski static void bnxt_get_eth_ctrl_stats(struct net_device *dev, 4027782bc00aSJakub Kicinski struct ethtool_eth_ctrl_stats *ctrl_stats) 4028782bc00aSJakub Kicinski { 4029782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4030782bc00aSJakub Kicinski u64 *rx; 4031782bc00aSJakub Kicinski 4032782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4033782bc00aSJakub Kicinski return; 4034782bc00aSJakub Kicinski 4035782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4036782bc00aSJakub Kicinski ctrl_stats->MACControlFramesReceived = 4037782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); 4038782bc00aSJakub Kicinski } 4039782bc00aSJakub Kicinski 4040782bc00aSJakub Kicinski static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { 4041782bc00aSJakub Kicinski { 0, 64 }, 4042782bc00aSJakub Kicinski { 65, 127 }, 4043782bc00aSJakub Kicinski { 128, 255 }, 4044782bc00aSJakub Kicinski { 256, 511 }, 4045782bc00aSJakub Kicinski { 512, 1023 }, 4046782bc00aSJakub Kicinski { 1024, 1518 }, 4047782bc00aSJakub Kicinski { 1519, 2047 }, 4048782bc00aSJakub Kicinski { 2048, 4095 }, 4049782bc00aSJakub Kicinski { 4096, 9216 }, 4050782bc00aSJakub Kicinski { 9217, 16383 }, 4051782bc00aSJakub Kicinski {} 4052782bc00aSJakub Kicinski }; 4053782bc00aSJakub Kicinski 4054782bc00aSJakub Kicinski static void bnxt_get_rmon_stats(struct net_device *dev, 4055782bc00aSJakub Kicinski struct ethtool_rmon_stats *rmon_stats, 4056782bc00aSJakub Kicinski const struct ethtool_rmon_hist_range **ranges) 4057782bc00aSJakub Kicinski { 4058782bc00aSJakub Kicinski struct bnxt *bp = netdev_priv(dev); 4059782bc00aSJakub Kicinski u64 *rx, *tx; 4060782bc00aSJakub Kicinski 4061782bc00aSJakub Kicinski if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) 4062782bc00aSJakub Kicinski return; 4063782bc00aSJakub Kicinski 4064782bc00aSJakub Kicinski rx = bp->port_stats.sw_stats; 4065782bc00aSJakub Kicinski tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; 4066782bc00aSJakub Kicinski 4067782bc00aSJakub Kicinski rmon_stats->jabbers = 4068782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); 4069782bc00aSJakub Kicinski rmon_stats->oversize_pkts = 4070782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); 4071782bc00aSJakub Kicinski rmon_stats->undersize_pkts = 4072782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); 4073782bc00aSJakub Kicinski 4074782bc00aSJakub Kicinski rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); 4075782bc00aSJakub Kicinski rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); 4076782bc00aSJakub Kicinski rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); 4077782bc00aSJakub Kicinski rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); 4078782bc00aSJakub Kicinski rmon_stats->hist[4] = 4079782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); 4080782bc00aSJakub Kicinski rmon_stats->hist[5] = 4081782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); 4082782bc00aSJakub Kicinski rmon_stats->hist[6] = 4083782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); 4084782bc00aSJakub Kicinski rmon_stats->hist[7] = 4085782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); 4086782bc00aSJakub Kicinski rmon_stats->hist[8] = 4087782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); 4088782bc00aSJakub Kicinski rmon_stats->hist[9] = 4089782bc00aSJakub Kicinski BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); 4090782bc00aSJakub Kicinski 4091782bc00aSJakub Kicinski rmon_stats->hist_tx[0] = 4092782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); 4093782bc00aSJakub Kicinski rmon_stats->hist_tx[1] = 4094782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); 4095782bc00aSJakub Kicinski rmon_stats->hist_tx[2] = 4096782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); 4097782bc00aSJakub Kicinski rmon_stats->hist_tx[3] = 4098782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); 4099782bc00aSJakub Kicinski rmon_stats->hist_tx[4] = 4100782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); 4101782bc00aSJakub Kicinski rmon_stats->hist_tx[5] = 4102782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); 4103782bc00aSJakub Kicinski rmon_stats->hist_tx[6] = 4104782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); 4105782bc00aSJakub Kicinski rmon_stats->hist_tx[7] = 4106782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); 4107782bc00aSJakub Kicinski rmon_stats->hist_tx[8] = 4108782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); 4109782bc00aSJakub Kicinski rmon_stats->hist_tx[9] = 4110782bc00aSJakub Kicinski BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); 4111782bc00aSJakub Kicinski 4112782bc00aSJakub Kicinski *ranges = bnxt_rmon_ranges; 4113782bc00aSJakub Kicinski } 4114782bc00aSJakub Kicinski 4115eb513658SMichael Chan void bnxt_ethtool_free(struct bnxt *bp) 4116eb513658SMichael Chan { 4117eb513658SMichael Chan kfree(bp->test_info); 4118eb513658SMichael Chan bp->test_info = NULL; 4119eb513658SMichael Chan } 4120eb513658SMichael Chan 4121c0c050c5SMichael Chan const struct ethtool_ops bnxt_ethtool_ops = { 4122f704d243SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 4123f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES | 4124f704d243SJakub Kicinski ETHTOOL_COALESCE_USECS_IRQ | 4125f704d243SJakub Kicinski ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 4126f704d243SJakub Kicinski ETHTOOL_COALESCE_STATS_BLOCK_USECS | 41273fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 41283fcbdbd5SMichael Chan ETHTOOL_COALESCE_USE_CQE, 412900c04a92SMichael Chan .get_link_ksettings = bnxt_get_link_ksettings, 413000c04a92SMichael Chan .set_link_ksettings = bnxt_set_link_ksettings, 4131c9ca5c3aSJakub Kicinski .get_fec_stats = bnxt_get_fec_stats, 41328b277589SMichael Chan .get_fecparam = bnxt_get_fecparam, 4133ccd6a9dcSMichael Chan .set_fecparam = bnxt_set_fecparam, 4134423cffcfSJakub Kicinski .get_pause_stats = bnxt_get_pause_stats, 4135c0c050c5SMichael Chan .get_pauseparam = bnxt_get_pauseparam, 4136c0c050c5SMichael Chan .set_pauseparam = bnxt_set_pauseparam, 4137c0c050c5SMichael Chan .get_drvinfo = bnxt_get_drvinfo, 4138b5d600b0SVasundhara Volam .get_regs_len = bnxt_get_regs_len, 4139b5d600b0SVasundhara Volam .get_regs = bnxt_get_regs, 41408e202366SMichael Chan .get_wol = bnxt_get_wol, 41415282db6cSMichael Chan .set_wol = bnxt_set_wol, 4142c0c050c5SMichael Chan .get_coalesce = bnxt_get_coalesce, 4143c0c050c5SMichael Chan .set_coalesce = bnxt_set_coalesce, 4144c0c050c5SMichael Chan .get_msglevel = bnxt_get_msglevel, 4145c0c050c5SMichael Chan .set_msglevel = bnxt_set_msglevel, 4146c0c050c5SMichael Chan .get_sset_count = bnxt_get_sset_count, 4147c0c050c5SMichael Chan .get_strings = bnxt_get_strings, 4148c0c050c5SMichael Chan .get_ethtool_stats = bnxt_get_ethtool_stats, 4149c0c050c5SMichael Chan .set_ringparam = bnxt_set_ringparam, 4150c0c050c5SMichael Chan .get_ringparam = bnxt_get_ringparam, 4151c0c050c5SMichael Chan .get_channels = bnxt_get_channels, 4152c0c050c5SMichael Chan .set_channels = bnxt_set_channels, 4153c0c050c5SMichael Chan .get_rxnfc = bnxt_get_rxnfc, 4154a011952aSMichael Chan .set_rxnfc = bnxt_set_rxnfc, 4155c0c050c5SMichael Chan .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, 4156c0c050c5SMichael Chan .get_rxfh_key_size = bnxt_get_rxfh_key_size, 4157c0c050c5SMichael Chan .get_rxfh = bnxt_get_rxfh, 4158bd3191b5SMichael Chan .set_rxfh = bnxt_set_rxfh, 4159c0c050c5SMichael Chan .flash_device = bnxt_flash_device, 4160c0c050c5SMichael Chan .get_eeprom_len = bnxt_get_eeprom_len, 4161c0c050c5SMichael Chan .get_eeprom = bnxt_get_eeprom, 4162c0c050c5SMichael Chan .set_eeprom = bnxt_set_eeprom, 4163c0c050c5SMichael Chan .get_link = bnxt_get_link, 416472b34f04SMichael Chan .get_eee = bnxt_get_eee, 416572b34f04SMichael Chan .set_eee = bnxt_set_eee, 416642ee18feSAjit Khaparde .get_module_info = bnxt_get_module_info, 416742ee18feSAjit Khaparde .get_module_eeprom = bnxt_get_module_eeprom, 41687ef3d390SVikas Gupta .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, 41695ad2cbeeSMichael Chan .nway_reset = bnxt_nway_reset, 41705ad2cbeeSMichael Chan .set_phys_id = bnxt_set_phys_id, 4171eb513658SMichael Chan .self_test = bnxt_self_test, 4172118612d5SMichael Chan .get_ts_info = bnxt_get_ts_info, 417349f7972fSVasundhara Volam .reset = bnxt_reset, 41740b0eacf3SVasundhara Volam .set_dump = bnxt_set_dump, 41756c5657d0SVasundhara Volam .get_dump_flag = bnxt_get_dump_flag, 41766c5657d0SVasundhara Volam .get_dump_data = bnxt_get_dump_data, 4177782bc00aSJakub Kicinski .get_eth_phy_stats = bnxt_get_eth_phy_stats, 4178782bc00aSJakub Kicinski .get_eth_mac_stats = bnxt_get_eth_mac_stats, 4179782bc00aSJakub Kicinski .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, 4180782bc00aSJakub Kicinski .get_rmon_stats = bnxt_get_rmon_stats, 4181c0c050c5SMichael Chan }; 4182