1/* 2 * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. 3 * Copyright(c) 2006 Chris Snook <csnook@redhat.com> 4 * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> 5 * 6 * Derived from Intel e1000 driver 7 * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 * more details. 18 * 19 * You should have received a copy of the GNU General Public License along with 20 * this program; if not, write to the Free Software Foundation, Inc., 59 21 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 */ 23 24#include <linux/types.h> 25#include <linux/pci.h> 26#include <linux/ethtool.h> 27#include <linux/netdevice.h> 28#include <linux/mii.h> 29#include <asm/uaccess.h> 30 31#include "atl1.h" 32 33struct atl1_stats { 34 char stat_string[ETH_GSTRING_LEN]; 35 int sizeof_stat; 36 int stat_offset; 37}; 38 39#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \ 40 offsetof(struct atl1_adapter, m) 41 42static struct atl1_stats atl1_gstrings_stats[] = { 43 {"rx_packets", ATL1_STAT(soft_stats.rx_packets)}, 44 {"tx_packets", ATL1_STAT(soft_stats.tx_packets)}, 45 {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)}, 46 {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, 47 {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, 48 {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, 49 {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, 50 {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, 51 {"multicast", ATL1_STAT(soft_stats.multicast)}, 52 {"collisions", ATL1_STAT(soft_stats.collisions)}, 53 {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, 54 {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, 55 {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)}, 56 {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)}, 57 {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)}, 58 {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, 59 {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)}, 60 {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)}, 61 {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)}, 62 {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)}, 63 {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)}, 64 {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)}, 65 {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)}, 66 {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)}, 67 {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)}, 68 {"tx_underun", ATL1_STAT(soft_stats.tx_underun)}, 69 {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)}, 70 {"tx_pause", ATL1_STAT(soft_stats.tx_pause)}, 71 {"rx_pause", ATL1_STAT(soft_stats.rx_pause)}, 72 {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)}, 73 {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)} 74}; 75 76static void atl1_get_ethtool_stats(struct net_device *netdev, 77 struct ethtool_stats *stats, u64 *data) 78{ 79 struct atl1_adapter *adapter = netdev_priv(netdev); 80 int i; 81 char *p; 82 83 for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { 84 p = (char *)adapter+atl1_gstrings_stats[i].stat_offset; 85 data[i] = (atl1_gstrings_stats[i].sizeof_stat == 86 sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 87 } 88 89} 90 91static int atl1_get_stats_count(struct net_device *netdev) 92{ 93 return ARRAY_SIZE(atl1_gstrings_stats); 94} 95 96static int atl1_get_settings(struct net_device *netdev, 97 struct ethtool_cmd *ecmd) 98{ 99 struct atl1_adapter *adapter = netdev_priv(netdev); 100 struct atl1_hw *hw = &adapter->hw; 101 102 ecmd->supported = (SUPPORTED_10baseT_Half | 103 SUPPORTED_10baseT_Full | 104 SUPPORTED_100baseT_Half | 105 SUPPORTED_100baseT_Full | 106 SUPPORTED_1000baseT_Full | 107 SUPPORTED_Autoneg | SUPPORTED_TP); 108 ecmd->advertising = ADVERTISED_TP; 109 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 110 hw->media_type == MEDIA_TYPE_1000M_FULL) { 111 ecmd->advertising |= ADVERTISED_Autoneg; 112 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) { 113 ecmd->advertising |= ADVERTISED_Autoneg; 114 ecmd->advertising |= 115 (ADVERTISED_10baseT_Half | 116 ADVERTISED_10baseT_Full | 117 ADVERTISED_100baseT_Half | 118 ADVERTISED_100baseT_Full | 119 ADVERTISED_1000baseT_Full); 120 } 121 else 122 ecmd->advertising |= (ADVERTISED_1000baseT_Full); 123 } 124 ecmd->port = PORT_TP; 125 ecmd->phy_address = 0; 126 ecmd->transceiver = XCVR_INTERNAL; 127 128 if (netif_carrier_ok(adapter->netdev)) { 129 u16 link_speed, link_duplex; 130 atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); 131 ecmd->speed = link_speed; 132 if (link_duplex == FULL_DUPLEX) 133 ecmd->duplex = DUPLEX_FULL; 134 else 135 ecmd->duplex = DUPLEX_HALF; 136 } else { 137 ecmd->speed = -1; 138 ecmd->duplex = -1; 139 } 140 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 141 hw->media_type == MEDIA_TYPE_1000M_FULL) 142 ecmd->autoneg = AUTONEG_ENABLE; 143 else 144 ecmd->autoneg = AUTONEG_DISABLE; 145 146 return 0; 147} 148 149static int atl1_set_settings(struct net_device *netdev, 150 struct ethtool_cmd *ecmd) 151{ 152 struct atl1_adapter *adapter = netdev_priv(netdev); 153 struct atl1_hw *hw = &adapter->hw; 154 u16 phy_data; 155 int ret_val = 0; 156 u16 old_media_type = hw->media_type; 157 158 if (netif_running(adapter->netdev)) { 159 dev_dbg(&adapter->pdev->dev, "ethtool shutting down adapter\n"); 160 atl1_down(adapter); 161 } 162 163 if (ecmd->autoneg == AUTONEG_ENABLE) 164 hw->media_type = MEDIA_TYPE_AUTO_SENSOR; 165 else { 166 if (ecmd->speed == SPEED_1000) { 167 if (ecmd->duplex != DUPLEX_FULL) { 168 dev_warn(&adapter->pdev->dev, 169 "can't force to 1000M half duplex\n"); 170 ret_val = -EINVAL; 171 goto exit_sset; 172 } 173 hw->media_type = MEDIA_TYPE_1000M_FULL; 174 } else if (ecmd->speed == SPEED_100) { 175 if (ecmd->duplex == DUPLEX_FULL) { 176 hw->media_type = MEDIA_TYPE_100M_FULL; 177 } else 178 hw->media_type = MEDIA_TYPE_100M_HALF; 179 } else { 180 if (ecmd->duplex == DUPLEX_FULL) 181 hw->media_type = MEDIA_TYPE_10M_FULL; 182 else 183 hw->media_type = MEDIA_TYPE_10M_HALF; 184 } 185 } 186 switch (hw->media_type) { 187 case MEDIA_TYPE_AUTO_SENSOR: 188 ecmd->advertising = 189 ADVERTISED_10baseT_Half | 190 ADVERTISED_10baseT_Full | 191 ADVERTISED_100baseT_Half | 192 ADVERTISED_100baseT_Full | 193 ADVERTISED_1000baseT_Full | 194 ADVERTISED_Autoneg | ADVERTISED_TP; 195 break; 196 case MEDIA_TYPE_1000M_FULL: 197 ecmd->advertising = 198 ADVERTISED_1000baseT_Full | 199 ADVERTISED_Autoneg | ADVERTISED_TP; 200 break; 201 default: 202 ecmd->advertising = 0; 203 break; 204 } 205 if (atl1_phy_setup_autoneg_adv(hw)) { 206 ret_val = -EINVAL; 207 dev_warn(&adapter->pdev->dev, 208 "invalid ethtool speed/duplex setting\n"); 209 goto exit_sset; 210 } 211 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 212 hw->media_type == MEDIA_TYPE_1000M_FULL) 213 phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; 214 else { 215 switch (hw->media_type) { 216 case MEDIA_TYPE_100M_FULL: 217 phy_data = 218 MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | 219 MII_CR_RESET; 220 break; 221 case MEDIA_TYPE_100M_HALF: 222 phy_data = MII_CR_SPEED_100 | MII_CR_RESET; 223 break; 224 case MEDIA_TYPE_10M_FULL: 225 phy_data = 226 MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; 227 break; 228 default: /* MEDIA_TYPE_10M_HALF: */ 229 phy_data = MII_CR_SPEED_10 | MII_CR_RESET; 230 break; 231 } 232 } 233 atl1_write_phy_reg(hw, MII_BMCR, phy_data); 234exit_sset: 235 if (ret_val) 236 hw->media_type = old_media_type; 237 238 if (netif_running(adapter->netdev)) { 239 dev_dbg(&adapter->pdev->dev, "ethtool starting adapter\n"); 240 atl1_up(adapter); 241 } else if (!ret_val) { 242 dev_dbg(&adapter->pdev->dev, "ethtool resetting adapter\n"); 243 atl1_reset(adapter); 244 } 245 return ret_val; 246} 247 248static void atl1_get_drvinfo(struct net_device *netdev, 249 struct ethtool_drvinfo *drvinfo) 250{ 251 struct atl1_adapter *adapter = netdev_priv(netdev); 252 253 strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver)); 254 strncpy(drvinfo->version, atl1_driver_version, 255 sizeof(drvinfo->version)); 256 strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); 257 strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 258 sizeof(drvinfo->bus_info)); 259 drvinfo->eedump_len = ATL1_EEDUMP_LEN; 260} 261 262static void atl1_get_wol(struct net_device *netdev, 263 struct ethtool_wolinfo *wol) 264{ 265 struct atl1_adapter *adapter = netdev_priv(netdev); 266 267 wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; 268 wol->wolopts = 0; 269 if (adapter->wol & ATL1_WUFC_EX) 270 wol->wolopts |= WAKE_UCAST; 271 if (adapter->wol & ATL1_WUFC_MC) 272 wol->wolopts |= WAKE_MCAST; 273 if (adapter->wol & ATL1_WUFC_BC) 274 wol->wolopts |= WAKE_BCAST; 275 if (adapter->wol & ATL1_WUFC_MAG) 276 wol->wolopts |= WAKE_MAGIC; 277 return; 278} 279 280static int atl1_set_wol(struct net_device *netdev, 281 struct ethtool_wolinfo *wol) 282{ 283 struct atl1_adapter *adapter = netdev_priv(netdev); 284 285 if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) 286 return -EOPNOTSUPP; 287 adapter->wol = 0; 288 if (wol->wolopts & WAKE_UCAST) 289 adapter->wol |= ATL1_WUFC_EX; 290 if (wol->wolopts & WAKE_MCAST) 291 adapter->wol |= ATL1_WUFC_MC; 292 if (wol->wolopts & WAKE_BCAST) 293 adapter->wol |= ATL1_WUFC_BC; 294 if (wol->wolopts & WAKE_MAGIC) 295 adapter->wol |= ATL1_WUFC_MAG; 296 return 0; 297} 298 299static void atl1_get_ringparam(struct net_device *netdev, 300 struct ethtool_ringparam *ring) 301{ 302 struct atl1_adapter *adapter = netdev_priv(netdev); 303 struct atl1_tpd_ring *txdr = &adapter->tpd_ring; 304 struct atl1_rfd_ring *rxdr = &adapter->rfd_ring; 305 306 ring->rx_max_pending = ATL1_MAX_RFD; 307 ring->tx_max_pending = ATL1_MAX_TPD; 308 ring->rx_mini_max_pending = 0; 309 ring->rx_jumbo_max_pending = 0; 310 ring->rx_pending = rxdr->count; 311 ring->tx_pending = txdr->count; 312 ring->rx_mini_pending = 0; 313 ring->rx_jumbo_pending = 0; 314} 315 316static int atl1_set_ringparam(struct net_device *netdev, 317 struct ethtool_ringparam *ring) 318{ 319 struct atl1_adapter *adapter = netdev_priv(netdev); 320 struct atl1_tpd_ring *tpdr = &adapter->tpd_ring; 321 struct atl1_rrd_ring *rrdr = &adapter->rrd_ring; 322 struct atl1_rfd_ring *rfdr = &adapter->rfd_ring; 323 324 struct atl1_tpd_ring tpd_old, tpd_new; 325 struct atl1_rfd_ring rfd_old, rfd_new; 326 struct atl1_rrd_ring rrd_old, rrd_new; 327 struct atl1_ring_header rhdr_old, rhdr_new; 328 int err; 329 330 tpd_old = adapter->tpd_ring; 331 rfd_old = adapter->rfd_ring; 332 rrd_old = adapter->rrd_ring; 333 rhdr_old = adapter->ring_header; 334 335 if (netif_running(adapter->netdev)) 336 atl1_down(adapter); 337 338 rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD); 339 rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD : 340 rfdr->count; 341 rfdr->count = (rfdr->count + 3) & ~3; 342 rrdr->count = rfdr->count; 343 344 tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD); 345 tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD : 346 tpdr->count; 347 tpdr->count = (tpdr->count + 3) & ~3; 348 349 if (netif_running(adapter->netdev)) { 350 /* try to get new resources before deleting old */ 351 err = atl1_setup_ring_resources(adapter); 352 if (err) 353 goto err_setup_ring; 354 355 /* 356 * save the new, restore the old in order to free it, 357 * then restore the new back again 358 */ 359 360 rfd_new = adapter->rfd_ring; 361 rrd_new = adapter->rrd_ring; 362 tpd_new = adapter->tpd_ring; 363 rhdr_new = adapter->ring_header; 364 adapter->rfd_ring = rfd_old; 365 adapter->rrd_ring = rrd_old; 366 adapter->tpd_ring = tpd_old; 367 adapter->ring_header = rhdr_old; 368 atl1_free_ring_resources(adapter); 369 adapter->rfd_ring = rfd_new; 370 adapter->rrd_ring = rrd_new; 371 adapter->tpd_ring = tpd_new; 372 adapter->ring_header = rhdr_new; 373 374 err = atl1_up(adapter); 375 if (err) 376 return err; 377 } 378 return 0; 379 380err_setup_ring: 381 adapter->rfd_ring = rfd_old; 382 adapter->rrd_ring = rrd_old; 383 adapter->tpd_ring = tpd_old; 384 adapter->ring_header = rhdr_old; 385 atl1_up(adapter); 386 return err; 387} 388 389static void atl1_get_pauseparam(struct net_device *netdev, 390 struct ethtool_pauseparam *epause) 391{ 392 struct atl1_adapter *adapter = netdev_priv(netdev); 393 struct atl1_hw *hw = &adapter->hw; 394 395 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 396 hw->media_type == MEDIA_TYPE_1000M_FULL) { 397 epause->autoneg = AUTONEG_ENABLE; 398 } else { 399 epause->autoneg = AUTONEG_DISABLE; 400 } 401 epause->rx_pause = 1; 402 epause->tx_pause = 1; 403} 404 405static int atl1_set_pauseparam(struct net_device *netdev, 406 struct ethtool_pauseparam *epause) 407{ 408 struct atl1_adapter *adapter = netdev_priv(netdev); 409 struct atl1_hw *hw = &adapter->hw; 410 411 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 412 hw->media_type == MEDIA_TYPE_1000M_FULL) { 413 epause->autoneg = AUTONEG_ENABLE; 414 } else { 415 epause->autoneg = AUTONEG_DISABLE; 416 } 417 418 epause->rx_pause = 1; 419 epause->tx_pause = 1; 420 421 return 0; 422} 423 424static u32 atl1_get_rx_csum(struct net_device *netdev) 425{ 426 return 1; 427} 428 429static void atl1_get_strings(struct net_device *netdev, u32 stringset, 430 u8 *data) 431{ 432 u8 *p = data; 433 int i; 434 435 switch (stringset) { 436 case ETH_SS_STATS: 437 for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { 438 memcpy(p, atl1_gstrings_stats[i].stat_string, 439 ETH_GSTRING_LEN); 440 p += ETH_GSTRING_LEN; 441 } 442 break; 443 } 444} 445 446static int atl1_nway_reset(struct net_device *netdev) 447{ 448 struct atl1_adapter *adapter = netdev_priv(netdev); 449 struct atl1_hw *hw = &adapter->hw; 450 451 if (netif_running(netdev)) { 452 u16 phy_data; 453 atl1_down(adapter); 454 455 if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || 456 hw->media_type == MEDIA_TYPE_1000M_FULL) { 457 phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; 458 } else { 459 switch (hw->media_type) { 460 case MEDIA_TYPE_100M_FULL: 461 phy_data = MII_CR_FULL_DUPLEX | 462 MII_CR_SPEED_100 | MII_CR_RESET; 463 break; 464 case MEDIA_TYPE_100M_HALF: 465 phy_data = MII_CR_SPEED_100 | MII_CR_RESET; 466 break; 467 case MEDIA_TYPE_10M_FULL: 468 phy_data = MII_CR_FULL_DUPLEX | 469 MII_CR_SPEED_10 | MII_CR_RESET; 470 break; 471 default: /* MEDIA_TYPE_10M_HALF */ 472 phy_data = MII_CR_SPEED_10 | MII_CR_RESET; 473 } 474 } 475 atl1_write_phy_reg(hw, MII_BMCR, phy_data); 476 atl1_up(adapter); 477 } 478 return 0; 479} 480 481const struct ethtool_ops atl1_ethtool_ops = { 482 .get_settings = atl1_get_settings, 483 .set_settings = atl1_set_settings, 484 .get_drvinfo = atl1_get_drvinfo, 485 .get_wol = atl1_get_wol, 486 .set_wol = atl1_set_wol, 487 .get_ringparam = atl1_get_ringparam, 488 .set_ringparam = atl1_set_ringparam, 489 .get_pauseparam = atl1_get_pauseparam, 490 .set_pauseparam = atl1_set_pauseparam, 491 .get_rx_csum = atl1_get_rx_csum, 492 .get_tx_csum = ethtool_op_get_tx_csum, 493 .set_tx_csum = ethtool_op_set_tx_hw_csum, 494 .get_link = ethtool_op_get_link, 495 .get_sg = ethtool_op_get_sg, 496 .set_sg = ethtool_op_set_sg, 497 .get_strings = atl1_get_strings, 498 .nway_reset = atl1_nway_reset, 499 .get_ethtool_stats = atl1_get_ethtool_stats, 500 .get_stats_count = atl1_get_stats_count, 501 .get_tso = ethtool_op_get_tso, 502 .set_tso = ethtool_op_set_tso, 503}; 504