1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/pci.h> 5 #include <linux/phy.h> 6 #include <linux/netdevice.h> 7 8 #include "../libwx/wx_ethtool.h" 9 #include "../libwx/wx_type.h" 10 #include "../libwx/wx_lib.h" 11 #include "../libwx/wx_hw.h" 12 #include "ngbe_ethtool.h" 13 #include "ngbe_type.h" 14 15 static void ngbe_get_wol(struct net_device *netdev, 16 struct ethtool_wolinfo *wol) 17 { 18 struct wx *wx = netdev_priv(netdev); 19 20 if (!wx->wol_hw_supported) 21 return; 22 wol->supported = WAKE_MAGIC; 23 wol->wolopts = 0; 24 if (wx->wol & WX_PSR_WKUP_CTL_MAG) 25 wol->wolopts |= WAKE_MAGIC; 26 } 27 28 static int ngbe_set_wol(struct net_device *netdev, 29 struct ethtool_wolinfo *wol) 30 { 31 struct wx *wx = netdev_priv(netdev); 32 struct pci_dev *pdev = wx->pdev; 33 34 if (!wx->wol_hw_supported) 35 return -EOPNOTSUPP; 36 37 wx->wol = 0; 38 if (wol->wolopts & WAKE_MAGIC) 39 wx->wol = WX_PSR_WKUP_CTL_MAG; 40 netdev->wol_enabled = !!(wx->wol); 41 wr32(wx, WX_PSR_WKUP_CTL, wx->wol); 42 device_set_wakeup_enable(&pdev->dev, netdev->wol_enabled); 43 44 return 0; 45 } 46 47 static int ngbe_set_ringparam(struct net_device *netdev, 48 struct ethtool_ringparam *ring, 49 struct kernel_ethtool_ringparam *kernel_ring, 50 struct netlink_ext_ack *extack) 51 { 52 struct wx *wx = netdev_priv(netdev); 53 u32 new_rx_count, new_tx_count; 54 struct wx_ring *temp_ring; 55 int i; 56 57 new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD); 58 new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE); 59 60 new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD); 61 new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE); 62 63 if (new_tx_count == wx->tx_ring_count && 64 new_rx_count == wx->rx_ring_count) 65 return 0; 66 67 if (!netif_running(wx->netdev)) { 68 for (i = 0; i < wx->num_tx_queues; i++) 69 wx->tx_ring[i]->count = new_tx_count; 70 for (i = 0; i < wx->num_rx_queues; i++) 71 wx->rx_ring[i]->count = new_rx_count; 72 wx->tx_ring_count = new_tx_count; 73 wx->rx_ring_count = new_rx_count; 74 75 return 0; 76 } 77 78 /* allocate temporary buffer to store rings in */ 79 i = max_t(int, wx->num_tx_queues, wx->num_rx_queues); 80 temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL); 81 if (!temp_ring) 82 return -ENOMEM; 83 84 ngbe_down(wx); 85 86 wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring); 87 kvfree(temp_ring); 88 89 wx_configure(wx); 90 ngbe_up(wx); 91 92 return 0; 93 } 94 95 static int ngbe_set_channels(struct net_device *dev, 96 struct ethtool_channels *ch) 97 { 98 int err; 99 100 err = wx_set_channels(dev, ch); 101 if (err < 0) 102 return err; 103 104 /* use setup TC to update any traffic class queue mapping */ 105 return ngbe_setup_tc(dev, netdev_get_num_tc(dev)); 106 } 107 108 static const struct ethtool_ops ngbe_ethtool_ops = { 109 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 110 ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, 111 .get_drvinfo = wx_get_drvinfo, 112 .get_link = ethtool_op_get_link, 113 .get_link_ksettings = wx_get_link_ksettings, 114 .set_link_ksettings = wx_set_link_ksettings, 115 .nway_reset = wx_nway_reset, 116 .get_wol = ngbe_get_wol, 117 .set_wol = ngbe_set_wol, 118 .get_sset_count = wx_get_sset_count, 119 .get_strings = wx_get_strings, 120 .get_ethtool_stats = wx_get_ethtool_stats, 121 .get_eth_mac_stats = wx_get_mac_stats, 122 .get_pause_stats = wx_get_pause_stats, 123 .get_pauseparam = wx_get_pauseparam, 124 .set_pauseparam = wx_set_pauseparam, 125 .get_ringparam = wx_get_ringparam, 126 .set_ringparam = ngbe_set_ringparam, 127 .get_coalesce = wx_get_coalesce, 128 .set_coalesce = wx_set_coalesce, 129 .get_channels = wx_get_channels, 130 .set_channels = ngbe_set_channels, 131 .get_msglevel = wx_get_msglevel, 132 .set_msglevel = wx_set_msglevel, 133 }; 134 135 void ngbe_set_ethtool_ops(struct net_device *netdev) 136 { 137 netdev->ethtool_ops = &ngbe_ethtool_ops; 138 } 139