Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
atl1e_ethtool.c
Go to the documentation of this file.
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 #include <linux/slab.h>
26 
27 #include "atl1e.h"
28 
29 static int atl1e_get_settings(struct net_device *netdev,
30  struct ethtool_cmd *ecmd)
31 {
32  struct atl1e_adapter *adapter = netdev_priv(netdev);
33  struct atl1e_hw *hw = &adapter->hw;
34 
40  SUPPORTED_TP);
41  if (hw->nic_type == athr_l1e)
43 
44  ecmd->advertising = ADVERTISED_TP;
45 
47  ecmd->advertising |= hw->autoneg_advertised;
48 
49  ecmd->port = PORT_TP;
50  ecmd->phy_address = 0;
51  ecmd->transceiver = XCVR_INTERNAL;
52 
53  if (adapter->link_speed != SPEED_0) {
54  ethtool_cmd_speed_set(ecmd, adapter->link_speed);
55  if (adapter->link_duplex == FULL_DUPLEX)
56  ecmd->duplex = DUPLEX_FULL;
57  else
58  ecmd->duplex = DUPLEX_HALF;
59  } else {
60  ethtool_cmd_speed_set(ecmd, -1);
61  ecmd->duplex = -1;
62  }
63 
64  ecmd->autoneg = AUTONEG_ENABLE;
65  return 0;
66 }
67 
68 static int atl1e_set_settings(struct net_device *netdev,
69  struct ethtool_cmd *ecmd)
70 {
71  struct atl1e_adapter *adapter = netdev_priv(netdev);
72  struct atl1e_hw *hw = &adapter->hw;
73 
74  while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
75  msleep(1);
76 
77  if (ecmd->autoneg == AUTONEG_ENABLE) {
78  u16 adv4, adv9;
79 
80  if ((ecmd->advertising&ADVERTISE_1000_FULL)) {
81  if (hw->nic_type == athr_l1e) {
82  hw->autoneg_advertised =
83  ecmd->advertising & AT_ADV_MASK;
84  } else {
85  clear_bit(__AT_RESETTING, &adapter->flags);
86  return -EINVAL;
87  }
88  } else if (ecmd->advertising&ADVERTISE_1000_HALF) {
89  clear_bit(__AT_RESETTING, &adapter->flags);
90  return -EINVAL;
91  } else {
92  hw->autoneg_advertised =
93  ecmd->advertising & AT_ADV_MASK;
94  }
95  ecmd->advertising = hw->autoneg_advertised |
97 
98  adv4 = hw->mii_autoneg_adv_reg & ~ADVERTISE_ALL;
101  adv4 |= ADVERTISE_10HALF;
103  adv4 |= ADVERTISE_10FULL;
105  adv4 |= ADVERTISE_100HALF;
107  adv4 |= ADVERTISE_100FULL;
109  adv9 |= ADVERTISE_1000FULL;
110 
111  if (adv4 != hw->mii_autoneg_adv_reg ||
112  adv9 != hw->mii_1000t_ctrl_reg) {
113  hw->mii_autoneg_adv_reg = adv4;
114  hw->mii_1000t_ctrl_reg = adv9;
115  hw->re_autoneg = true;
116  }
117 
118  } else {
119  clear_bit(__AT_RESETTING, &adapter->flags);
120  return -EINVAL;
121  }
122 
123  /* reset the link */
124 
125  if (netif_running(adapter->netdev)) {
126  atl1e_down(adapter);
127  atl1e_up(adapter);
128  } else
129  atl1e_reset_hw(&adapter->hw);
130 
131  clear_bit(__AT_RESETTING, &adapter->flags);
132  return 0;
133 }
134 
135 static u32 atl1e_get_msglevel(struct net_device *netdev)
136 {
137 #ifdef DBG
138  return 1;
139 #else
140  return 0;
141 #endif
142 }
143 
144 static int atl1e_get_regs_len(struct net_device *netdev)
145 {
146  return AT_REGS_LEN * sizeof(u32);
147 }
148 
149 static void atl1e_get_regs(struct net_device *netdev,
150  struct ethtool_regs *regs, void *p)
151 {
152  struct atl1e_adapter *adapter = netdev_priv(netdev);
153  struct atl1e_hw *hw = &adapter->hw;
154  u32 *regs_buff = p;
155  u16 phy_data;
156 
157  memset(p, 0, AT_REGS_LEN * sizeof(u32));
158 
159  regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
160 
161  regs_buff[0] = AT_READ_REG(hw, REG_VPD_CAP);
162  regs_buff[1] = AT_READ_REG(hw, REG_SPI_FLASH_CTRL);
163  regs_buff[2] = AT_READ_REG(hw, REG_SPI_FLASH_CONFIG);
164  regs_buff[3] = AT_READ_REG(hw, REG_TWSI_CTRL);
165  regs_buff[4] = AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL);
166  regs_buff[5] = AT_READ_REG(hw, REG_MASTER_CTRL);
167  regs_buff[6] = AT_READ_REG(hw, REG_MANUAL_TIMER_INIT);
168  regs_buff[7] = AT_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT);
169  regs_buff[8] = AT_READ_REG(hw, REG_GPHY_CTRL);
170  regs_buff[9] = AT_READ_REG(hw, REG_CMBDISDMA_TIMER);
171  regs_buff[10] = AT_READ_REG(hw, REG_IDLE_STATUS);
172  regs_buff[11] = AT_READ_REG(hw, REG_MDIO_CTRL);
173  regs_buff[12] = AT_READ_REG(hw, REG_SERDES_LOCK);
174  regs_buff[13] = AT_READ_REG(hw, REG_MAC_CTRL);
175  regs_buff[14] = AT_READ_REG(hw, REG_MAC_IPG_IFG);
176  regs_buff[15] = AT_READ_REG(hw, REG_MAC_STA_ADDR);
177  regs_buff[16] = AT_READ_REG(hw, REG_MAC_STA_ADDR+4);
178  regs_buff[17] = AT_READ_REG(hw, REG_RX_HASH_TABLE);
179  regs_buff[18] = AT_READ_REG(hw, REG_RX_HASH_TABLE+4);
180  regs_buff[19] = AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL);
181  regs_buff[20] = AT_READ_REG(hw, REG_MTU);
182  regs_buff[21] = AT_READ_REG(hw, REG_WOL_CTRL);
183  regs_buff[22] = AT_READ_REG(hw, REG_SRAM_TRD_ADDR);
184  regs_buff[23] = AT_READ_REG(hw, REG_SRAM_TRD_LEN);
185  regs_buff[24] = AT_READ_REG(hw, REG_SRAM_RXF_ADDR);
186  regs_buff[25] = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
187  regs_buff[26] = AT_READ_REG(hw, REG_SRAM_TXF_ADDR);
188  regs_buff[27] = AT_READ_REG(hw, REG_SRAM_TXF_LEN);
189  regs_buff[28] = AT_READ_REG(hw, REG_SRAM_TCPH_ADDR);
190  regs_buff[29] = AT_READ_REG(hw, REG_SRAM_PKTH_ADDR);
191 
192  atl1e_read_phy_reg(hw, MII_BMCR, &phy_data);
193  regs_buff[73] = (u32)phy_data;
194  atl1e_read_phy_reg(hw, MII_BMSR, &phy_data);
195  regs_buff[74] = (u32)phy_data;
196 }
197 
198 static int atl1e_get_eeprom_len(struct net_device *netdev)
199 {
200  struct atl1e_adapter *adapter = netdev_priv(netdev);
201 
202  if (!atl1e_check_eeprom_exist(&adapter->hw))
203  return AT_EEPROM_LEN;
204  else
205  return 0;
206 }
207 
208 static int atl1e_get_eeprom(struct net_device *netdev,
209  struct ethtool_eeprom *eeprom, u8 *bytes)
210 {
211  struct atl1e_adapter *adapter = netdev_priv(netdev);
212  struct atl1e_hw *hw = &adapter->hw;
213  u32 *eeprom_buff;
214  int first_dword, last_dword;
215  int ret_val = 0;
216  int i;
217 
218  if (eeprom->len == 0)
219  return -EINVAL;
220 
221  if (atl1e_check_eeprom_exist(hw)) /* not exist */
222  return -EINVAL;
223 
224  eeprom->magic = hw->vendor_id | (hw->device_id << 16);
225 
226  first_dword = eeprom->offset >> 2;
227  last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
228 
229  eeprom_buff = kmalloc(sizeof(u32) *
230  (last_dword - first_dword + 1), GFP_KERNEL);
231  if (eeprom_buff == NULL)
232  return -ENOMEM;
233 
234  for (i = first_dword; i < last_dword; i++) {
235  if (!atl1e_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
236  kfree(eeprom_buff);
237  return -EIO;
238  }
239  }
240 
241  memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
242  eeprom->len);
243  kfree(eeprom_buff);
244 
245  return ret_val;
246 }
247 
248 static int atl1e_set_eeprom(struct net_device *netdev,
249  struct ethtool_eeprom *eeprom, u8 *bytes)
250 {
251  struct atl1e_adapter *adapter = netdev_priv(netdev);
252  struct atl1e_hw *hw = &adapter->hw;
253  u32 *eeprom_buff;
254  u32 *ptr;
255  int first_dword, last_dword;
256  int ret_val = 0;
257  int i;
258 
259  if (eeprom->len == 0)
260  return -EOPNOTSUPP;
261 
262  if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
263  return -EINVAL;
264 
265  first_dword = eeprom->offset >> 2;
266  last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
267  eeprom_buff = kmalloc(AT_EEPROM_LEN, GFP_KERNEL);
268  if (eeprom_buff == NULL)
269  return -ENOMEM;
270 
271  ptr = eeprom_buff;
272 
273  if (eeprom->offset & 3) {
274  /* need read/modify/write of first changed EEPROM word */
275  /* only the second byte of the word is being modified */
276  if (!atl1e_read_eeprom(hw, first_dword * 4, &(eeprom_buff[0]))) {
277  ret_val = -EIO;
278  goto out;
279  }
280  ptr++;
281  }
282  if (((eeprom->offset + eeprom->len) & 3)) {
283  /* need read/modify/write of last changed EEPROM word */
284  /* only the first byte of the word is being modified */
285 
286  if (!atl1e_read_eeprom(hw, last_dword * 4,
287  &(eeprom_buff[last_dword - first_dword]))) {
288  ret_val = -EIO;
289  goto out;
290  }
291  }
292 
293  /* Device's eeprom is always little-endian, word addressable */
294  memcpy(ptr, bytes, eeprom->len);
295 
296  for (i = 0; i < last_dword - first_dword + 1; i++) {
297  if (!atl1e_write_eeprom(hw, ((first_dword + i) * 4),
298  eeprom_buff[i])) {
299  ret_val = -EIO;
300  goto out;
301  }
302  }
303 out:
304  kfree(eeprom_buff);
305  return ret_val;
306 }
307 
308 static void atl1e_get_drvinfo(struct net_device *netdev,
309  struct ethtool_drvinfo *drvinfo)
310 {
311  struct atl1e_adapter *adapter = netdev_priv(netdev);
312 
313  strlcpy(drvinfo->driver, atl1e_driver_name, sizeof(drvinfo->driver));
315  sizeof(drvinfo->version));
316  strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
317  strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
318  sizeof(drvinfo->bus_info));
319  drvinfo->n_stats = 0;
320  drvinfo->testinfo_len = 0;
321  drvinfo->regdump_len = atl1e_get_regs_len(netdev);
322  drvinfo->eedump_len = atl1e_get_eeprom_len(netdev);
323 }
324 
325 static void atl1e_get_wol(struct net_device *netdev,
326  struct ethtool_wolinfo *wol)
327 {
328  struct atl1e_adapter *adapter = netdev_priv(netdev);
329 
330  wol->supported = WAKE_MAGIC | WAKE_PHY;
331  wol->wolopts = 0;
332 
333  if (adapter->wol & AT_WUFC_EX)
334  wol->wolopts |= WAKE_UCAST;
335  if (adapter->wol & AT_WUFC_MC)
336  wol->wolopts |= WAKE_MCAST;
337  if (adapter->wol & AT_WUFC_BC)
338  wol->wolopts |= WAKE_BCAST;
339  if (adapter->wol & AT_WUFC_MAG)
340  wol->wolopts |= WAKE_MAGIC;
341  if (adapter->wol & AT_WUFC_LNKC)
342  wol->wolopts |= WAKE_PHY;
343 }
344 
345 static int atl1e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
346 {
347  struct atl1e_adapter *adapter = netdev_priv(netdev);
348 
349  if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
351  return -EOPNOTSUPP;
352  /* these settings will always override what we currently have */
353  adapter->wol = 0;
354 
355  if (wol->wolopts & WAKE_MAGIC)
356  adapter->wol |= AT_WUFC_MAG;
357  if (wol->wolopts & WAKE_PHY)
358  adapter->wol |= AT_WUFC_LNKC;
359 
360  device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
361 
362  return 0;
363 }
364 
365 static int atl1e_nway_reset(struct net_device *netdev)
366 {
367  struct atl1e_adapter *adapter = netdev_priv(netdev);
368  if (netif_running(netdev))
369  atl1e_reinit_locked(adapter);
370  return 0;
371 }
372 
373 static const struct ethtool_ops atl1e_ethtool_ops = {
374  .get_settings = atl1e_get_settings,
375  .set_settings = atl1e_set_settings,
376  .get_drvinfo = atl1e_get_drvinfo,
377  .get_regs_len = atl1e_get_regs_len,
378  .get_regs = atl1e_get_regs,
379  .get_wol = atl1e_get_wol,
380  .set_wol = atl1e_set_wol,
381  .get_msglevel = atl1e_get_msglevel,
382  .nway_reset = atl1e_nway_reset,
383  .get_link = ethtool_op_get_link,
384  .get_eeprom_len = atl1e_get_eeprom_len,
385  .get_eeprom = atl1e_get_eeprom,
386  .set_eeprom = atl1e_set_eeprom,
387 };
388 
389 void atl1e_set_ethtool_ops(struct net_device *netdev)
390 {
391  SET_ETHTOOL_OPS(netdev, &atl1e_ethtool_ops);
392 }