Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.28 405 lines 12 kB view raw
1/* 2 * Copyright(c) 2007 Atheros Corporation. All rights reserved. 3 * 4 * Derived from Intel e1000 driver 5 * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program; if not, write to the Free Software Foundation, Inc., 59 19 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 */ 22 23#include <linux/netdevice.h> 24#include <linux/ethtool.h> 25 26#include "atl1e.h" 27 28static int atl1e_get_settings(struct net_device *netdev, 29 struct ethtool_cmd *ecmd) 30{ 31 struct atl1e_adapter *adapter = netdev_priv(netdev); 32 struct atl1e_hw *hw = &adapter->hw; 33 34 ecmd->supported = (SUPPORTED_10baseT_Half | 35 SUPPORTED_10baseT_Full | 36 SUPPORTED_100baseT_Half | 37 SUPPORTED_100baseT_Full | 38 SUPPORTED_Autoneg | 39 SUPPORTED_TP); 40 if (hw->nic_type == athr_l1e) 41 ecmd->supported |= SUPPORTED_1000baseT_Full; 42 43 ecmd->advertising = ADVERTISED_TP; 44 45 ecmd->advertising |= ADVERTISED_Autoneg; 46 ecmd->advertising |= hw->autoneg_advertised; 47 48 ecmd->port = PORT_TP; 49 ecmd->phy_address = 0; 50 ecmd->transceiver = XCVR_INTERNAL; 51 52 if (adapter->link_speed != SPEED_0) { 53 ecmd->speed = adapter->link_speed; 54 if (adapter->link_duplex == FULL_DUPLEX) 55 ecmd->duplex = DUPLEX_FULL; 56 else 57 ecmd->duplex = DUPLEX_HALF; 58 } else { 59 ecmd->speed = -1; 60 ecmd->duplex = -1; 61 } 62 63 ecmd->autoneg = AUTONEG_ENABLE; 64 return 0; 65} 66 67static int atl1e_set_settings(struct net_device *netdev, 68 struct ethtool_cmd *ecmd) 69{ 70 struct atl1e_adapter *adapter = netdev_priv(netdev); 71 struct atl1e_hw *hw = &adapter->hw; 72 73 while (test_and_set_bit(__AT_RESETTING, &adapter->flags)) 74 msleep(1); 75 76 if (ecmd->autoneg == AUTONEG_ENABLE) { 77 u16 adv4, adv9; 78 79 if ((ecmd->advertising&ADVERTISE_1000_FULL)) { 80 if (hw->nic_type == athr_l1e) { 81 hw->autoneg_advertised = 82 ecmd->advertising & AT_ADV_MASK; 83 } else { 84 clear_bit(__AT_RESETTING, &adapter->flags); 85 return -EINVAL; 86 } 87 } else if (ecmd->advertising&ADVERTISE_1000_HALF) { 88 clear_bit(__AT_RESETTING, &adapter->flags); 89 return -EINVAL; 90 } else { 91 hw->autoneg_advertised = 92 ecmd->advertising & AT_ADV_MASK; 93 } 94 ecmd->advertising = hw->autoneg_advertised | 95 ADVERTISED_TP | ADVERTISED_Autoneg; 96 97 adv4 = hw->mii_autoneg_adv_reg & ~MII_AR_SPEED_MASK; 98 adv9 = hw->mii_1000t_ctrl_reg & ~MII_AT001_CR_1000T_SPEED_MASK; 99 if (hw->autoneg_advertised & ADVERTISE_10_HALF) 100 adv4 |= MII_AR_10T_HD_CAPS; 101 if (hw->autoneg_advertised & ADVERTISE_10_FULL) 102 adv4 |= MII_AR_10T_FD_CAPS; 103 if (hw->autoneg_advertised & ADVERTISE_100_HALF) 104 adv4 |= MII_AR_100TX_HD_CAPS; 105 if (hw->autoneg_advertised & ADVERTISE_100_FULL) 106 adv4 |= MII_AR_100TX_FD_CAPS; 107 if (hw->autoneg_advertised & ADVERTISE_1000_FULL) 108 adv9 |= MII_AT001_CR_1000T_FD_CAPS; 109 110 if (adv4 != hw->mii_autoneg_adv_reg || 111 adv9 != hw->mii_1000t_ctrl_reg) { 112 hw->mii_autoneg_adv_reg = adv4; 113 hw->mii_1000t_ctrl_reg = adv9; 114 hw->re_autoneg = true; 115 } 116 117 } else { 118 clear_bit(__AT_RESETTING, &adapter->flags); 119 return -EINVAL; 120 } 121 122 /* reset the link */ 123 124 if (netif_running(adapter->netdev)) { 125 atl1e_down(adapter); 126 atl1e_up(adapter); 127 } else 128 atl1e_reset_hw(&adapter->hw); 129 130 clear_bit(__AT_RESETTING, &adapter->flags); 131 return 0; 132} 133 134static u32 atl1e_get_tx_csum(struct net_device *netdev) 135{ 136 return (netdev->features & NETIF_F_HW_CSUM) != 0; 137} 138 139static u32 atl1e_get_msglevel(struct net_device *netdev) 140{ 141#ifdef DBG 142 return 1; 143#else 144 return 0; 145#endif 146} 147 148static void atl1e_set_msglevel(struct net_device *netdev, u32 data) 149{ 150} 151 152static int atl1e_get_regs_len(struct net_device *netdev) 153{ 154 return AT_REGS_LEN * sizeof(u32); 155} 156 157static void atl1e_get_regs(struct net_device *netdev, 158 struct ethtool_regs *regs, void *p) 159{ 160 struct atl1e_adapter *adapter = netdev_priv(netdev); 161 struct atl1e_hw *hw = &adapter->hw; 162 u32 *regs_buff = p; 163 u16 phy_data; 164 165 memset(p, 0, AT_REGS_LEN * sizeof(u32)); 166 167 regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; 168 169 regs_buff[0] = AT_READ_REG(hw, REG_VPD_CAP); 170 regs_buff[1] = AT_READ_REG(hw, REG_SPI_FLASH_CTRL); 171 regs_buff[2] = AT_READ_REG(hw, REG_SPI_FLASH_CONFIG); 172 regs_buff[3] = AT_READ_REG(hw, REG_TWSI_CTRL); 173 regs_buff[4] = AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL); 174 regs_buff[5] = AT_READ_REG(hw, REG_MASTER_CTRL); 175 regs_buff[6] = AT_READ_REG(hw, REG_MANUAL_TIMER_INIT); 176 regs_buff[7] = AT_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT); 177 regs_buff[8] = AT_READ_REG(hw, REG_GPHY_CTRL); 178 regs_buff[9] = AT_READ_REG(hw, REG_CMBDISDMA_TIMER); 179 regs_buff[10] = AT_READ_REG(hw, REG_IDLE_STATUS); 180 regs_buff[11] = AT_READ_REG(hw, REG_MDIO_CTRL); 181 regs_buff[12] = AT_READ_REG(hw, REG_SERDES_LOCK); 182 regs_buff[13] = AT_READ_REG(hw, REG_MAC_CTRL); 183 regs_buff[14] = AT_READ_REG(hw, REG_MAC_IPG_IFG); 184 regs_buff[15] = AT_READ_REG(hw, REG_MAC_STA_ADDR); 185 regs_buff[16] = AT_READ_REG(hw, REG_MAC_STA_ADDR+4); 186 regs_buff[17] = AT_READ_REG(hw, REG_RX_HASH_TABLE); 187 regs_buff[18] = AT_READ_REG(hw, REG_RX_HASH_TABLE+4); 188 regs_buff[19] = AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL); 189 regs_buff[20] = AT_READ_REG(hw, REG_MTU); 190 regs_buff[21] = AT_READ_REG(hw, REG_WOL_CTRL); 191 regs_buff[22] = AT_READ_REG(hw, REG_SRAM_TRD_ADDR); 192 regs_buff[23] = AT_READ_REG(hw, REG_SRAM_TRD_LEN); 193 regs_buff[24] = AT_READ_REG(hw, REG_SRAM_RXF_ADDR); 194 regs_buff[25] = AT_READ_REG(hw, REG_SRAM_RXF_LEN); 195 regs_buff[26] = AT_READ_REG(hw, REG_SRAM_TXF_ADDR); 196 regs_buff[27] = AT_READ_REG(hw, REG_SRAM_TXF_LEN); 197 regs_buff[28] = AT_READ_REG(hw, REG_SRAM_TCPH_ADDR); 198 regs_buff[29] = AT_READ_REG(hw, REG_SRAM_PKTH_ADDR); 199 200 atl1e_read_phy_reg(hw, MII_BMCR, &phy_data); 201 regs_buff[73] = (u32)phy_data; 202 atl1e_read_phy_reg(hw, MII_BMSR, &phy_data); 203 regs_buff[74] = (u32)phy_data; 204} 205 206static int atl1e_get_eeprom_len(struct net_device *netdev) 207{ 208 struct atl1e_adapter *adapter = netdev_priv(netdev); 209 210 if (!atl1e_check_eeprom_exist(&adapter->hw)) 211 return AT_EEPROM_LEN; 212 else 213 return 0; 214} 215 216static int atl1e_get_eeprom(struct net_device *netdev, 217 struct ethtool_eeprom *eeprom, u8 *bytes) 218{ 219 struct atl1e_adapter *adapter = netdev_priv(netdev); 220 struct atl1e_hw *hw = &adapter->hw; 221 u32 *eeprom_buff; 222 int first_dword, last_dword; 223 int ret_val = 0; 224 int i; 225 226 if (eeprom->len == 0) 227 return -EINVAL; 228 229 if (atl1e_check_eeprom_exist(hw)) /* not exist */ 230 return -EINVAL; 231 232 eeprom->magic = hw->vendor_id | (hw->device_id << 16); 233 234 first_dword = eeprom->offset >> 2; 235 last_dword = (eeprom->offset + eeprom->len - 1) >> 2; 236 237 eeprom_buff = kmalloc(sizeof(u32) * 238 (last_dword - first_dword + 1), GFP_KERNEL); 239 if (eeprom_buff == NULL) 240 return -ENOMEM; 241 242 for (i = first_dword; i < last_dword; i++) { 243 if (!atl1e_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) { 244 kfree(eeprom_buff); 245 return -EIO; 246 } 247 } 248 249 memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3), 250 eeprom->len); 251 kfree(eeprom_buff); 252 253 return ret_val; 254} 255 256static int atl1e_set_eeprom(struct net_device *netdev, 257 struct ethtool_eeprom *eeprom, u8 *bytes) 258{ 259 struct atl1e_adapter *adapter = netdev_priv(netdev); 260 struct atl1e_hw *hw = &adapter->hw; 261 u32 *eeprom_buff; 262 u32 *ptr; 263 int first_dword, last_dword; 264 int ret_val = 0; 265 int i; 266 267 if (eeprom->len == 0) 268 return -EOPNOTSUPP; 269 270 if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) 271 return -EINVAL; 272 273 first_dword = eeprom->offset >> 2; 274 last_dword = (eeprom->offset + eeprom->len - 1) >> 2; 275 eeprom_buff = kmalloc(AT_EEPROM_LEN, GFP_KERNEL); 276 if (eeprom_buff == NULL) 277 return -ENOMEM; 278 279 ptr = (u32 *)eeprom_buff; 280 281 if (eeprom->offset & 3) { 282 /* need read/modify/write of first changed EEPROM word */ 283 /* only the second byte of the word is being modified */ 284 if (!atl1e_read_eeprom(hw, first_dword * 4, &(eeprom_buff[0]))) { 285 ret_val = -EIO; 286 goto out; 287 } 288 ptr++; 289 } 290 if (((eeprom->offset + eeprom->len) & 3)) { 291 /* need read/modify/write of last changed EEPROM word */ 292 /* only the first byte of the word is being modified */ 293 294 if (!atl1e_read_eeprom(hw, last_dword * 4, 295 &(eeprom_buff[last_dword - first_dword]))) { 296 ret_val = -EIO; 297 goto out; 298 } 299 } 300 301 /* Device's eeprom is always little-endian, word addressable */ 302 memcpy(ptr, bytes, eeprom->len); 303 304 for (i = 0; i < last_dword - first_dword + 1; i++) { 305 if (!atl1e_write_eeprom(hw, ((first_dword + i) * 4), 306 eeprom_buff[i])) { 307 ret_val = -EIO; 308 goto out; 309 } 310 } 311out: 312 kfree(eeprom_buff); 313 return ret_val; 314} 315 316static void atl1e_get_drvinfo(struct net_device *netdev, 317 struct ethtool_drvinfo *drvinfo) 318{ 319 struct atl1e_adapter *adapter = netdev_priv(netdev); 320 321 strncpy(drvinfo->driver, atl1e_driver_name, 32); 322 strncpy(drvinfo->version, atl1e_driver_version, 32); 323 strncpy(drvinfo->fw_version, "L1e", 32); 324 strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); 325 drvinfo->n_stats = 0; 326 drvinfo->testinfo_len = 0; 327 drvinfo->regdump_len = atl1e_get_regs_len(netdev); 328 drvinfo->eedump_len = atl1e_get_eeprom_len(netdev); 329} 330 331static void atl1e_get_wol(struct net_device *netdev, 332 struct ethtool_wolinfo *wol) 333{ 334 struct atl1e_adapter *adapter = netdev_priv(netdev); 335 336 wol->supported = WAKE_MAGIC | WAKE_PHY; 337 wol->wolopts = 0; 338 339 if (adapter->wol & AT_WUFC_EX) 340 wol->wolopts |= WAKE_UCAST; 341 if (adapter->wol & AT_WUFC_MC) 342 wol->wolopts |= WAKE_MCAST; 343 if (adapter->wol & AT_WUFC_BC) 344 wol->wolopts |= WAKE_BCAST; 345 if (adapter->wol & AT_WUFC_MAG) 346 wol->wolopts |= WAKE_MAGIC; 347 if (adapter->wol & AT_WUFC_LNKC) 348 wol->wolopts |= WAKE_PHY; 349 350 return; 351} 352 353static int atl1e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) 354{ 355 struct atl1e_adapter *adapter = netdev_priv(netdev); 356 357 if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | 358 WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) 359 return -EOPNOTSUPP; 360 /* these settings will always override what we currently have */ 361 adapter->wol = 0; 362 363 if (wol->wolopts & WAKE_MAGIC) 364 adapter->wol |= AT_WUFC_MAG; 365 if (wol->wolopts & WAKE_PHY) 366 adapter->wol |= AT_WUFC_LNKC; 367 368 return 0; 369} 370 371static int atl1e_nway_reset(struct net_device *netdev) 372{ 373 struct atl1e_adapter *adapter = netdev_priv(netdev); 374 if (netif_running(netdev)) 375 atl1e_reinit_locked(adapter); 376 return 0; 377} 378 379static struct ethtool_ops atl1e_ethtool_ops = { 380 .get_settings = atl1e_get_settings, 381 .set_settings = atl1e_set_settings, 382 .get_drvinfo = atl1e_get_drvinfo, 383 .get_regs_len = atl1e_get_regs_len, 384 .get_regs = atl1e_get_regs, 385 .get_wol = atl1e_get_wol, 386 .set_wol = atl1e_set_wol, 387 .get_msglevel = atl1e_get_msglevel, 388 .set_msglevel = atl1e_set_msglevel, 389 .nway_reset = atl1e_nway_reset, 390 .get_link = ethtool_op_get_link, 391 .get_eeprom_len = atl1e_get_eeprom_len, 392 .get_eeprom = atl1e_get_eeprom, 393 .set_eeprom = atl1e_set_eeprom, 394 .get_tx_csum = atl1e_get_tx_csum, 395 .get_sg = ethtool_op_get_sg, 396 .set_sg = ethtool_op_set_sg, 397#ifdef NETIF_F_TSO 398 .get_tso = ethtool_op_get_tso, 399#endif 400}; 401 402void atl1e_set_ethtool_ops(struct net_device *netdev) 403{ 404 SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops); 405}