| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 1 | /******************************************************************************* | 
|  | 2 |  | 
|  | 3 | Intel(R) 82576 Virtual Function Linux driver | 
|  | 4 | Copyright(c) 2009 Intel Corporation. | 
|  | 5 |  | 
|  | 6 | This program is free software; you can redistribute it and/or modify it | 
|  | 7 | under the terms and conditions of the GNU General Public License, | 
|  | 8 | version 2, as published by the Free Software Foundation. | 
|  | 9 |  | 
|  | 10 | This program is distributed in the hope it will be useful, but WITHOUT | 
|  | 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | 12 | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | 
|  | 13 | more details. | 
|  | 14 |  | 
|  | 15 | You should have received a copy of the GNU General Public License along with | 
|  | 16 | this program; if not, write to the Free Software Foundation, Inc., | 
|  | 17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 
|  | 18 |  | 
|  | 19 | The full GNU General Public License is included in this distribution in | 
|  | 20 | the file called "COPYING". | 
|  | 21 |  | 
|  | 22 | Contact Information: | 
|  | 23 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | 
|  | 24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
|  | 25 |  | 
|  | 26 | *******************************************************************************/ | 
|  | 27 |  | 
|  | 28 | /* ethtool support for igbvf */ | 
|  | 29 |  | 
|  | 30 | #include <linux/netdevice.h> | 
|  | 31 | #include <linux/ethtool.h> | 
|  | 32 | #include <linux/pci.h> | 
|  | 33 | #include <linux/vmalloc.h> | 
|  | 34 | #include <linux/delay.h> | 
|  | 35 |  | 
|  | 36 | #include "igbvf.h" | 
|  | 37 | #include <linux/if_vlan.h> | 
|  | 38 |  | 
|  | 39 |  | 
|  | 40 | struct igbvf_stats { | 
|  | 41 | char stat_string[ETH_GSTRING_LEN]; | 
|  | 42 | int sizeof_stat; | 
|  | 43 | int stat_offset; | 
|  | 44 | int base_stat_offset; | 
|  | 45 | }; | 
|  | 46 |  | 
|  | 47 | #define IGBVF_STAT(current, base) \ | 
|  | 48 | sizeof(((struct igbvf_adapter *)0)->current), \ | 
|  | 49 | offsetof(struct igbvf_adapter, current), \ | 
|  | 50 | offsetof(struct igbvf_adapter, base) | 
|  | 51 |  | 
|  | 52 | static const struct igbvf_stats igbvf_gstrings_stats[] = { | 
|  | 53 | { "rx_packets", IGBVF_STAT(stats.gprc, stats.base_gprc) }, | 
|  | 54 | { "tx_packets", IGBVF_STAT(stats.gptc, stats.base_gptc) }, | 
|  | 55 | { "rx_bytes", IGBVF_STAT(stats.gorc, stats.base_gorc) }, | 
|  | 56 | { "tx_bytes", IGBVF_STAT(stats.gotc, stats.base_gotc) }, | 
|  | 57 | { "multicast", IGBVF_STAT(stats.mprc, stats.base_mprc) }, | 
|  | 58 | { "lbrx_bytes", IGBVF_STAT(stats.gorlbc, stats.base_gorlbc) }, | 
|  | 59 | { "lbrx_packets", IGBVF_STAT(stats.gprlbc, stats.base_gprlbc) }, | 
|  | 60 | { "tx_restart_queue", IGBVF_STAT(restart_queue, zero_base) }, | 
|  | 61 | { "rx_long_byte_count", IGBVF_STAT(stats.gorc, stats.base_gorc) }, | 
|  | 62 | { "rx_csum_offload_good", IGBVF_STAT(hw_csum_good, zero_base) }, | 
|  | 63 | { "rx_csum_offload_errors", IGBVF_STAT(hw_csum_err, zero_base) }, | 
|  | 64 | { "rx_header_split", IGBVF_STAT(rx_hdr_split, zero_base) }, | 
|  | 65 | { "alloc_rx_buff_failed", IGBVF_STAT(alloc_rx_buff_failed, zero_base) }, | 
|  | 66 | }; | 
|  | 67 |  | 
|  | 68 | #define IGBVF_GLOBAL_STATS_LEN ARRAY_SIZE(igbvf_gstrings_stats) | 
|  | 69 |  | 
|  | 70 | static const char igbvf_gstrings_test[][ETH_GSTRING_LEN] = { | 
|  | 71 | "Link test   (on/offline)" | 
|  | 72 | }; | 
|  | 73 |  | 
|  | 74 | #define IGBVF_TEST_LEN ARRAY_SIZE(igbvf_gstrings_test) | 
|  | 75 |  | 
|  | 76 | static int igbvf_get_settings(struct net_device *netdev, | 
|  | 77 | struct ethtool_cmd *ecmd) | 
|  | 78 | { | 
|  | 79 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 80 | struct e1000_hw *hw = &adapter->hw; | 
|  | 81 | u32 status; | 
|  | 82 |  | 
|  | 83 | ecmd->supported   = SUPPORTED_1000baseT_Full; | 
|  | 84 |  | 
|  | 85 | ecmd->advertising = ADVERTISED_1000baseT_Full; | 
|  | 86 |  | 
|  | 87 | ecmd->port = -1; | 
|  | 88 | ecmd->transceiver = XCVR_DUMMY1; | 
|  | 89 |  | 
|  | 90 | status = er32(STATUS); | 
|  | 91 | if (status & E1000_STATUS_LU) { | 
|  | 92 | if (status & E1000_STATUS_SPEED_1000) | 
|  | 93 | ecmd->speed = 1000; | 
|  | 94 | else if (status & E1000_STATUS_SPEED_100) | 
|  | 95 | ecmd->speed = 100; | 
|  | 96 | else | 
|  | 97 | ecmd->speed = 10; | 
|  | 98 |  | 
|  | 99 | if (status & E1000_STATUS_FD) | 
|  | 100 | ecmd->duplex = DUPLEX_FULL; | 
|  | 101 | else | 
|  | 102 | ecmd->duplex = DUPLEX_HALF; | 
|  | 103 | } else { | 
|  | 104 | ecmd->speed = -1; | 
|  | 105 | ecmd->duplex = -1; | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | ecmd->autoneg = AUTONEG_DISABLE; | 
|  | 109 |  | 
|  | 110 | return 0; | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | static u32 igbvf_get_link(struct net_device *netdev) | 
|  | 114 | { | 
|  | 115 | return netif_carrier_ok(netdev); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | static int igbvf_set_settings(struct net_device *netdev, | 
|  | 119 | struct ethtool_cmd *ecmd) | 
|  | 120 | { | 
|  | 121 | return -EOPNOTSUPP; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | static void igbvf_get_pauseparam(struct net_device *netdev, | 
|  | 125 | struct ethtool_pauseparam *pause) | 
|  | 126 | { | 
|  | 127 | return; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | static int igbvf_set_pauseparam(struct net_device *netdev, | 
|  | 131 | struct ethtool_pauseparam *pause) | 
|  | 132 | { | 
|  | 133 | return -EOPNOTSUPP; | 
|  | 134 | } | 
|  | 135 |  | 
| Alexander Duyck | 0364d6f | 2009-05-06 10:25:01 +0000 | [diff] [blame] | 136 | static u32 igbvf_get_rx_csum(struct net_device *netdev) | 
|  | 137 | { | 
|  | 138 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 139 | return !(adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED); | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | static int igbvf_set_rx_csum(struct net_device *netdev, u32 data) | 
|  | 143 | { | 
|  | 144 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 145 |  | 
|  | 146 | if (data) | 
|  | 147 | adapter->flags &= ~IGBVF_FLAG_RX_CSUM_DISABLED; | 
|  | 148 | else | 
|  | 149 | adapter->flags |= IGBVF_FLAG_RX_CSUM_DISABLED; | 
|  | 150 |  | 
|  | 151 | return 0; | 
|  | 152 | } | 
|  | 153 |  | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 154 | static u32 igbvf_get_tx_csum(struct net_device *netdev) | 
|  | 155 | { | 
|  | 156 | return ((netdev->features & NETIF_F_IP_CSUM) != 0); | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | static int igbvf_set_tx_csum(struct net_device *netdev, u32 data) | 
|  | 160 | { | 
|  | 161 | if (data) | 
|  | 162 | netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); | 
|  | 163 | else | 
|  | 164 | netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); | 
|  | 165 | return 0; | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | static int igbvf_set_tso(struct net_device *netdev, u32 data) | 
|  | 169 | { | 
|  | 170 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 171 |  | 
|  | 172 | if (data) { | 
|  | 173 | netdev->features |= NETIF_F_TSO; | 
|  | 174 | netdev->features |= NETIF_F_TSO6; | 
|  | 175 | } else { | 
|  | 176 | netdev->features &= ~NETIF_F_TSO; | 
|  | 177 | netdev->features &= ~NETIF_F_TSO6; | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 178 | } | 
|  | 179 |  | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 180 | dev_info(&adapter->pdev->dev, "TSO is %s\n", | 
|  | 181 | data ? "Enabled" : "Disabled"); | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 182 | return 0; | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | static u32 igbvf_get_msglevel(struct net_device *netdev) | 
|  | 186 | { | 
|  | 187 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 188 | return adapter->msg_enable; | 
|  | 189 | } | 
|  | 190 |  | 
|  | 191 | static void igbvf_set_msglevel(struct net_device *netdev, u32 data) | 
|  | 192 | { | 
|  | 193 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 194 | adapter->msg_enable = data; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | static int igbvf_get_regs_len(struct net_device *netdev) | 
|  | 198 | { | 
|  | 199 | #define IGBVF_REGS_LEN 8 | 
|  | 200 | return IGBVF_REGS_LEN * sizeof(u32); | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | static void igbvf_get_regs(struct net_device *netdev, | 
|  | 204 | struct ethtool_regs *regs, void *p) | 
|  | 205 | { | 
|  | 206 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 207 | struct e1000_hw *hw = &adapter->hw; | 
|  | 208 | u32 *regs_buff = p; | 
|  | 209 | u8 revision_id; | 
|  | 210 |  | 
|  | 211 | memset(p, 0, IGBVF_REGS_LEN * sizeof(u32)); | 
|  | 212 |  | 
|  | 213 | pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id); | 
|  | 214 |  | 
|  | 215 | regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device; | 
|  | 216 |  | 
|  | 217 | regs_buff[0] = er32(CTRL); | 
|  | 218 | regs_buff[1] = er32(STATUS); | 
|  | 219 |  | 
|  | 220 | regs_buff[2] = er32(RDLEN(0)); | 
|  | 221 | regs_buff[3] = er32(RDH(0)); | 
|  | 222 | regs_buff[4] = er32(RDT(0)); | 
|  | 223 |  | 
|  | 224 | regs_buff[5] = er32(TDLEN(0)); | 
|  | 225 | regs_buff[6] = er32(TDH(0)); | 
|  | 226 | regs_buff[7] = er32(TDT(0)); | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 | static int igbvf_get_eeprom_len(struct net_device *netdev) | 
|  | 230 | { | 
|  | 231 | return 0; | 
|  | 232 | } | 
|  | 233 |  | 
|  | 234 | static int igbvf_get_eeprom(struct net_device *netdev, | 
|  | 235 | struct ethtool_eeprom *eeprom, u8 *bytes) | 
|  | 236 | { | 
|  | 237 | return -EOPNOTSUPP; | 
|  | 238 | } | 
|  | 239 |  | 
|  | 240 | static int igbvf_set_eeprom(struct net_device *netdev, | 
|  | 241 | struct ethtool_eeprom *eeprom, u8 *bytes) | 
|  | 242 | { | 
|  | 243 | return -EOPNOTSUPP; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | static void igbvf_get_drvinfo(struct net_device *netdev, | 
|  | 247 | struct ethtool_drvinfo *drvinfo) | 
|  | 248 | { | 
|  | 249 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 250 | char firmware_version[32] = "N/A"; | 
|  | 251 |  | 
|  | 252 | strncpy(drvinfo->driver,  igbvf_driver_name, 32); | 
|  | 253 | strncpy(drvinfo->version, igbvf_driver_version, 32); | 
|  | 254 | strncpy(drvinfo->fw_version, firmware_version, 32); | 
|  | 255 | strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); | 
|  | 256 | drvinfo->regdump_len = igbvf_get_regs_len(netdev); | 
|  | 257 | drvinfo->eedump_len = igbvf_get_eeprom_len(netdev); | 
|  | 258 | } | 
|  | 259 |  | 
|  | 260 | static void igbvf_get_ringparam(struct net_device *netdev, | 
|  | 261 | struct ethtool_ringparam *ring) | 
|  | 262 | { | 
|  | 263 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 264 | struct igbvf_ring *tx_ring = adapter->tx_ring; | 
|  | 265 | struct igbvf_ring *rx_ring = adapter->rx_ring; | 
|  | 266 |  | 
|  | 267 | ring->rx_max_pending = IGBVF_MAX_RXD; | 
|  | 268 | ring->tx_max_pending = IGBVF_MAX_TXD; | 
|  | 269 | ring->rx_mini_max_pending = 0; | 
|  | 270 | ring->rx_jumbo_max_pending = 0; | 
|  | 271 | ring->rx_pending = rx_ring->count; | 
|  | 272 | ring->tx_pending = tx_ring->count; | 
|  | 273 | ring->rx_mini_pending = 0; | 
|  | 274 | ring->rx_jumbo_pending = 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | static int igbvf_set_ringparam(struct net_device *netdev, | 
|  | 278 | struct ethtool_ringparam *ring) | 
|  | 279 | { | 
|  | 280 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 281 | struct igbvf_ring *temp_ring; | 
|  | 282 | int err; | 
|  | 283 | u32 new_rx_count, new_tx_count; | 
|  | 284 |  | 
|  | 285 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 
|  | 286 | return -EINVAL; | 
|  | 287 |  | 
|  | 288 | new_rx_count = max(ring->rx_pending, (u32)IGBVF_MIN_RXD); | 
|  | 289 | new_rx_count = min(new_rx_count, (u32)IGBVF_MAX_RXD); | 
|  | 290 | new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); | 
|  | 291 |  | 
|  | 292 | new_tx_count = max(ring->tx_pending, (u32)IGBVF_MIN_TXD); | 
|  | 293 | new_tx_count = min(new_tx_count, (u32)IGBVF_MAX_TXD); | 
|  | 294 | new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); | 
|  | 295 |  | 
|  | 296 | if ((new_tx_count == adapter->tx_ring->count) && | 
|  | 297 | (new_rx_count == adapter->rx_ring->count)) { | 
|  | 298 | /* nothing to do */ | 
|  | 299 | return 0; | 
|  | 300 | } | 
|  | 301 |  | 
|  | 302 | temp_ring = vmalloc(sizeof(struct igbvf_ring)); | 
|  | 303 | if (!temp_ring) | 
|  | 304 | return -ENOMEM; | 
|  | 305 |  | 
|  | 306 | while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state)) | 
|  | 307 | msleep(1); | 
|  | 308 |  | 
|  | 309 | if (netif_running(adapter->netdev)) | 
|  | 310 | igbvf_down(adapter); | 
|  | 311 |  | 
|  | 312 | /* | 
|  | 313 | * We can't just free everything and then setup again, | 
|  | 314 | * because the ISRs in MSI-X mode get passed pointers | 
|  | 315 | * to the tx and rx ring structs. | 
|  | 316 | */ | 
|  | 317 | if (new_tx_count != adapter->tx_ring->count) { | 
|  | 318 | memcpy(temp_ring, adapter->tx_ring, sizeof(struct igbvf_ring)); | 
|  | 319 |  | 
|  | 320 | temp_ring->count = new_tx_count; | 
|  | 321 | err = igbvf_setup_tx_resources(adapter, temp_ring); | 
|  | 322 | if (err) | 
|  | 323 | goto err_setup; | 
|  | 324 |  | 
|  | 325 | igbvf_free_tx_resources(adapter->tx_ring); | 
|  | 326 |  | 
|  | 327 | memcpy(adapter->tx_ring, temp_ring, sizeof(struct igbvf_ring)); | 
|  | 328 | } | 
|  | 329 |  | 
|  | 330 | if (new_rx_count != adapter->rx_ring->count) { | 
|  | 331 | memcpy(temp_ring, adapter->rx_ring, sizeof(struct igbvf_ring)); | 
|  | 332 |  | 
|  | 333 | temp_ring->count = new_rx_count; | 
|  | 334 | err = igbvf_setup_rx_resources(adapter, temp_ring); | 
|  | 335 | if (err) | 
|  | 336 | goto err_setup; | 
|  | 337 |  | 
|  | 338 | igbvf_free_rx_resources(adapter->rx_ring); | 
|  | 339 |  | 
|  | 340 | memcpy(adapter->rx_ring, temp_ring,sizeof(struct igbvf_ring)); | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | err = 0; | 
|  | 344 | err_setup: | 
|  | 345 | if (netif_running(adapter->netdev)) | 
|  | 346 | igbvf_up(adapter); | 
|  | 347 |  | 
|  | 348 | clear_bit(__IGBVF_RESETTING, &adapter->state); | 
|  | 349 | vfree(temp_ring); | 
|  | 350 | return err; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | static int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data) | 
|  | 354 | { | 
|  | 355 | struct e1000_hw *hw = &adapter->hw; | 
|  | 356 | *data = 0; | 
|  | 357 |  | 
|  | 358 | hw->mac.ops.check_for_link(hw); | 
|  | 359 |  | 
|  | 360 | if (!(er32(STATUS) & E1000_STATUS_LU)) | 
|  | 361 | *data = 1; | 
|  | 362 |  | 
|  | 363 | return *data; | 
|  | 364 | } | 
|  | 365 |  | 
|  | 366 | static int igbvf_get_self_test_count(struct net_device *netdev) | 
|  | 367 | { | 
|  | 368 | return IGBVF_TEST_LEN; | 
|  | 369 | } | 
|  | 370 |  | 
|  | 371 | static int igbvf_get_stats_count(struct net_device *netdev) | 
|  | 372 | { | 
|  | 373 | return IGBVF_GLOBAL_STATS_LEN; | 
|  | 374 | } | 
|  | 375 |  | 
|  | 376 | static void igbvf_diag_test(struct net_device *netdev, | 
|  | 377 | struct ethtool_test *eth_test, u64 *data) | 
|  | 378 | { | 
|  | 379 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 380 |  | 
|  | 381 | set_bit(__IGBVF_TESTING, &adapter->state); | 
|  | 382 |  | 
|  | 383 | /* | 
|  | 384 | * Link test performed before hardware reset so autoneg doesn't | 
|  | 385 | * interfere with test result | 
|  | 386 | */ | 
|  | 387 | if (igbvf_link_test(adapter, &data[0])) | 
|  | 388 | eth_test->flags |= ETH_TEST_FL_FAILED; | 
|  | 389 |  | 
|  | 390 | clear_bit(__IGBVF_TESTING, &adapter->state); | 
|  | 391 | msleep_interruptible(4 * 1000); | 
|  | 392 | } | 
|  | 393 |  | 
|  | 394 | static void igbvf_get_wol(struct net_device *netdev, | 
|  | 395 | struct ethtool_wolinfo *wol) | 
|  | 396 | { | 
|  | 397 | wol->supported = 0; | 
|  | 398 | wol->wolopts = 0; | 
|  | 399 |  | 
|  | 400 | return; | 
|  | 401 | } | 
|  | 402 |  | 
|  | 403 | static int igbvf_set_wol(struct net_device *netdev, | 
|  | 404 | struct ethtool_wolinfo *wol) | 
|  | 405 | { | 
|  | 406 | return -EOPNOTSUPP; | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | static int igbvf_phys_id(struct net_device *netdev, u32 data) | 
|  | 410 | { | 
|  | 411 | return 0; | 
|  | 412 | } | 
|  | 413 |  | 
|  | 414 | static int igbvf_get_coalesce(struct net_device *netdev, | 
|  | 415 | struct ethtool_coalesce *ec) | 
|  | 416 | { | 
|  | 417 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 418 |  | 
|  | 419 | if (adapter->itr_setting <= 3) | 
|  | 420 | ec->rx_coalesce_usecs = adapter->itr_setting; | 
|  | 421 | else | 
|  | 422 | ec->rx_coalesce_usecs = adapter->itr_setting >> 2; | 
|  | 423 |  | 
|  | 424 | return 0; | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | static int igbvf_set_coalesce(struct net_device *netdev, | 
|  | 428 | struct ethtool_coalesce *ec) | 
|  | 429 | { | 
|  | 430 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 431 | struct e1000_hw *hw = &adapter->hw; | 
|  | 432 |  | 
|  | 433 | if ((ec->rx_coalesce_usecs > IGBVF_MAX_ITR_USECS) || | 
|  | 434 | ((ec->rx_coalesce_usecs > 3) && | 
|  | 435 | (ec->rx_coalesce_usecs < IGBVF_MIN_ITR_USECS)) || | 
|  | 436 | (ec->rx_coalesce_usecs == 2)) | 
|  | 437 | return -EINVAL; | 
|  | 438 |  | 
|  | 439 | /* convert to rate of irq's per second */ | 
|  | 440 | if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) { | 
|  | 441 | adapter->itr = IGBVF_START_ITR; | 
|  | 442 | adapter->itr_setting = ec->rx_coalesce_usecs; | 
|  | 443 | } else { | 
|  | 444 | adapter->itr = ec->rx_coalesce_usecs << 2; | 
|  | 445 | adapter->itr_setting = adapter->itr; | 
|  | 446 | } | 
|  | 447 |  | 
|  | 448 | writel(adapter->itr, | 
|  | 449 | hw->hw_addr + adapter->rx_ring[0].itr_register); | 
|  | 450 |  | 
|  | 451 | return 0; | 
|  | 452 | } | 
|  | 453 |  | 
|  | 454 | static int igbvf_nway_reset(struct net_device *netdev) | 
|  | 455 | { | 
|  | 456 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 457 | if (netif_running(netdev)) | 
|  | 458 | igbvf_reinit_locked(adapter); | 
|  | 459 | return 0; | 
|  | 460 | } | 
|  | 461 |  | 
|  | 462 |  | 
|  | 463 | static void igbvf_get_ethtool_stats(struct net_device *netdev, | 
|  | 464 | struct ethtool_stats *stats, | 
|  | 465 | u64 *data) | 
|  | 466 | { | 
|  | 467 | struct igbvf_adapter *adapter = netdev_priv(netdev); | 
|  | 468 | int i; | 
|  | 469 |  | 
|  | 470 | igbvf_update_stats(adapter); | 
|  | 471 | for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) { | 
|  | 472 | char *p = (char *)adapter + | 
|  | 473 | igbvf_gstrings_stats[i].stat_offset; | 
|  | 474 | char *b = (char *)adapter + | 
|  | 475 | igbvf_gstrings_stats[i].base_stat_offset; | 
|  | 476 | data[i] = ((igbvf_gstrings_stats[i].sizeof_stat == | 
|  | 477 | sizeof(u64)) ? (*(u64 *)p - *(u64 *)b) : | 
|  | 478 | (*(u32 *)p - *(u32 *)b)); | 
|  | 479 | } | 
|  | 480 |  | 
|  | 481 | } | 
|  | 482 |  | 
|  | 483 | static void igbvf_get_strings(struct net_device *netdev, u32 stringset, | 
|  | 484 | u8 *data) | 
|  | 485 | { | 
|  | 486 | u8 *p = data; | 
|  | 487 | int i; | 
|  | 488 |  | 
|  | 489 | switch (stringset) { | 
|  | 490 | case ETH_SS_TEST: | 
|  | 491 | memcpy(data, *igbvf_gstrings_test, sizeof(igbvf_gstrings_test)); | 
|  | 492 | break; | 
|  | 493 | case ETH_SS_STATS: | 
|  | 494 | for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) { | 
|  | 495 | memcpy(p, igbvf_gstrings_stats[i].stat_string, | 
|  | 496 | ETH_GSTRING_LEN); | 
|  | 497 | p += ETH_GSTRING_LEN; | 
|  | 498 | } | 
|  | 499 | break; | 
|  | 500 | } | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | static const struct ethtool_ops igbvf_ethtool_ops = { | 
|  | 504 | .get_settings		= igbvf_get_settings, | 
|  | 505 | .set_settings		= igbvf_set_settings, | 
|  | 506 | .get_drvinfo		= igbvf_get_drvinfo, | 
|  | 507 | .get_regs_len		= igbvf_get_regs_len, | 
|  | 508 | .get_regs		= igbvf_get_regs, | 
|  | 509 | .get_wol		= igbvf_get_wol, | 
|  | 510 | .set_wol		= igbvf_set_wol, | 
|  | 511 | .get_msglevel		= igbvf_get_msglevel, | 
|  | 512 | .set_msglevel		= igbvf_set_msglevel, | 
|  | 513 | .nway_reset		= igbvf_nway_reset, | 
|  | 514 | .get_link		= igbvf_get_link, | 
|  | 515 | .get_eeprom_len		= igbvf_get_eeprom_len, | 
|  | 516 | .get_eeprom		= igbvf_get_eeprom, | 
|  | 517 | .set_eeprom		= igbvf_set_eeprom, | 
|  | 518 | .get_ringparam		= igbvf_get_ringparam, | 
|  | 519 | .set_ringparam		= igbvf_set_ringparam, | 
|  | 520 | .get_pauseparam		= igbvf_get_pauseparam, | 
|  | 521 | .set_pauseparam		= igbvf_set_pauseparam, | 
| Alexander Duyck | 0364d6f | 2009-05-06 10:25:01 +0000 | [diff] [blame] | 522 | .get_rx_csum            = igbvf_get_rx_csum, | 
|  | 523 | .set_rx_csum            = igbvf_set_rx_csum, | 
| Alexander Duyck | d4e0fe0 | 2009-04-07 14:37:34 +0000 | [diff] [blame] | 524 | .get_tx_csum		= igbvf_get_tx_csum, | 
|  | 525 | .set_tx_csum		= igbvf_set_tx_csum, | 
|  | 526 | .get_sg			= ethtool_op_get_sg, | 
|  | 527 | .set_sg			= ethtool_op_set_sg, | 
|  | 528 | .get_tso		= ethtool_op_get_tso, | 
|  | 529 | .set_tso		= igbvf_set_tso, | 
|  | 530 | .self_test		= igbvf_diag_test, | 
|  | 531 | .get_strings		= igbvf_get_strings, | 
|  | 532 | .phys_id		= igbvf_phys_id, | 
|  | 533 | .get_ethtool_stats	= igbvf_get_ethtool_stats, | 
|  | 534 | .self_test_count	= igbvf_get_self_test_count, | 
|  | 535 | .get_stats_count	= igbvf_get_stats_count, | 
|  | 536 | .get_coalesce		= igbvf_get_coalesce, | 
|  | 537 | .set_coalesce		= igbvf_set_coalesce, | 
|  | 538 | }; | 
|  | 539 |  | 
|  | 540 | void igbvf_set_ethtool_ops(struct net_device *netdev) | 
|  | 541 | { | 
|  | 542 | /* have to "undeclare" const on this struct to remove warnings */ | 
|  | 543 | SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&igbvf_ethtool_ops); | 
|  | 544 | } |