Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mdio.c
Go to the documentation of this file.
1 /*
2  * mdio.c: Generic support for MDIO-compatible transceivers
3  * Copyright 2006-2009 Solarflare Communications Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation, incorporated herein by reference.
8  */
9 
10 #include <linux/kernel.h>
11 #include <linux/capability.h>
12 #include <linux/errno.h>
13 #include <linux/ethtool.h>
14 #include <linux/mdio.h>
15 #include <linux/module.h>
16 
17 MODULE_DESCRIPTION("Generic support for MDIO-compatible transceivers");
18 MODULE_AUTHOR("Copyright 2006-2009 Solarflare Communications Inc.");
19 MODULE_LICENSE("GPL");
20 
29 int mdio45_probe(struct mdio_if_info *mdio, int prtad)
30 {
31  int mmd, stat2, devs1, devs2;
32 
33  /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY
34  * XS or DTE XS; give up if none is present. */
35  for (mmd = 1; mmd <= 5; mmd++) {
36  /* Is this MMD present? */
37  stat2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_STAT2);
38  if (stat2 < 0 ||
40  continue;
41 
42  /* It should tell us about all the other MMDs */
43  devs1 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS1);
44  devs2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS2);
45  if (devs1 < 0 || devs2 < 0)
46  continue;
47 
48  mdio->prtad = prtad;
49  mdio->mmds = devs1 | (devs2 << 16);
50  return 0;
51  }
52 
53  return -ENODEV;
54 }
56 
69 int mdio_set_flag(const struct mdio_if_info *mdio,
70  int prtad, int devad, u16 addr, int mask,
71  bool sense)
72 {
73  int old_val = mdio->mdio_read(mdio->dev, prtad, devad, addr);
74  int new_val;
75 
76  if (old_val < 0)
77  return old_val;
78  if (sense)
79  new_val = old_val | mask;
80  else
81  new_val = old_val & ~mask;
82  if (old_val == new_val)
83  return 0;
84  return mdio->mdio_write(mdio->dev, prtad, devad, addr, new_val);
85 }
87 
97 int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask)
98 {
99  int devad, reg;
100 
101  if (!mmd_mask) {
102  /* Use absence of XGMII faults in lieu of link state */
103  reg = mdio->mdio_read(mdio->dev, mdio->prtad,
105  return reg >= 0 && !(reg & MDIO_STAT2_RXFAULT);
106  }
107 
108  for (devad = 0; mmd_mask; devad++) {
109  if (mmd_mask & (1 << devad)) {
110  mmd_mask &= ~(1 << devad);
111 
112  /* Reset the latched status and fault flags */
113  mdio->mdio_read(mdio->dev, mdio->prtad,
114  devad, MDIO_STAT1);
115  if (devad == MDIO_MMD_PMAPMD || devad == MDIO_MMD_PCS ||
116  devad == MDIO_MMD_PHYXS || devad == MDIO_MMD_DTEXS)
117  mdio->mdio_read(mdio->dev, mdio->prtad,
118  devad, MDIO_STAT2);
119 
120  /* Check the current status and fault flags */
121  reg = mdio->mdio_read(mdio->dev, mdio->prtad,
122  devad, MDIO_STAT1);
123  if (reg < 0 ||
124  (reg & (MDIO_STAT1_FAULT | MDIO_STAT1_LSTATUS)) !=
126  return false;
127  }
128  }
129 
130  return true;
131 }
133 
140 int mdio45_nway_restart(const struct mdio_if_info *mdio)
141 {
142  if (!(mdio->mmds & MDIO_DEVS_AN))
143  return -EOPNOTSUPP;
144 
146  MDIO_AN_CTRL1_RESTART, true);
147  return 0;
148 }
150 
151 static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
152 {
153  u32 result = 0;
154  int reg;
155 
156  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, addr);
157  if (reg & ADVERTISE_10HALF)
158  result |= ADVERTISED_10baseT_Half;
159  if (reg & ADVERTISE_10FULL)
160  result |= ADVERTISED_10baseT_Full;
161  if (reg & ADVERTISE_100HALF)
162  result |= ADVERTISED_100baseT_Half;
163  if (reg & ADVERTISE_100FULL)
164  result |= ADVERTISED_100baseT_Full;
165  if (reg & ADVERTISE_PAUSE_CAP)
166  result |= ADVERTISED_Pause;
167  if (reg & ADVERTISE_PAUSE_ASYM)
168  result |= ADVERTISED_Asym_Pause;
169  return result;
170 }
171 
186 void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
187  struct ethtool_cmd *ecmd,
188  u32 npage_adv, u32 npage_lpa)
189 {
190  int reg;
191  u32 speed;
192 
195 
196  ecmd->transceiver = XCVR_INTERNAL;
197  ecmd->phy_address = mdio->prtad;
198  ecmd->mdio_support =
200 
201  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
202  MDIO_CTRL2);
203  switch (reg & MDIO_PMA_CTRL2_TYPE) {
207  case MDIO_PMA_CTRL2_10BT:
208  ecmd->port = PORT_TP;
209  ecmd->supported = SUPPORTED_TP;
210  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
211  MDIO_SPEED);
212  if (reg & MDIO_SPEED_10G)
214  if (reg & MDIO_PMA_SPEED_1000)
217  if (reg & MDIO_PMA_SPEED_100)
220  if (reg & MDIO_PMA_SPEED_10)
223  ecmd->advertising = ADVERTISED_TP;
224  break;
225 
227  ecmd->port = PORT_OTHER;
228  ecmd->supported = 0;
229  ecmd->advertising = 0;
230  break;
231 
235  ecmd->port = PORT_OTHER;
237  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
239  if (reg & MDIO_PMA_EXTABLE_10GBKX4)
241  if (reg & MDIO_PMA_EXTABLE_10GBKR)
243  if (reg & MDIO_PMA_EXTABLE_1000BKX)
245  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
247  if (reg & MDIO_PMA_10GBR_FECABLE_ABLE)
250  break;
251 
252  /* All the other defined modes are flavours of optical */
253  default:
254  ecmd->port = PORT_FIBRE;
255  ecmd->supported = SUPPORTED_FIBRE;
257  break;
258  }
259 
260  if (mdio->mmds & MDIO_DEVS_AN) {
261  ecmd->supported |= SUPPORTED_Autoneg;
262  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
263  MDIO_CTRL1);
264  if (reg & MDIO_AN_CTRL1_ENABLE) {
265  ecmd->autoneg = AUTONEG_ENABLE;
266  ecmd->advertising |=
268  mdio45_get_an(mdio, MDIO_AN_ADVERTISE) |
269  npage_adv;
270  } else {
271  ecmd->autoneg = AUTONEG_DISABLE;
272  }
273  } else {
274  ecmd->autoneg = AUTONEG_DISABLE;
275  }
276 
277  if (ecmd->autoneg) {
278  u32 modes = 0;
279  int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad,
281 
282  /* If AN is complete and successful, report best common
283  * mode, otherwise report best advertised mode. */
284  if (an_stat & MDIO_AN_STAT1_COMPLETE) {
285  ecmd->lp_advertising =
286  mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa;
287  if (an_stat & MDIO_AN_STAT1_LPABLE)
289  modes = ecmd->advertising & ecmd->lp_advertising;
290  }
291  if ((modes & ~ADVERTISED_Autoneg) == 0)
292  modes = ecmd->advertising;
293 
294  if (modes & (ADVERTISED_10000baseT_Full |
297  speed = SPEED_10000;
298  ecmd->duplex = DUPLEX_FULL;
299  } else if (modes & (ADVERTISED_1000baseT_Full |
302  speed = SPEED_1000;
303  ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half);
304  } else if (modes & (ADVERTISED_100baseT_Full |
306  speed = SPEED_100;
307  ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
308  } else {
309  speed = SPEED_10;
310  ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
311  }
312  } else {
313  /* Report forced settings */
314  reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
315  MDIO_CTRL1);
316  speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1)
317  * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
318  ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX ||
319  speed == SPEED_10000);
320  }
321 
322  ethtool_cmd_speed_set(ecmd, speed);
323 
324  /* 10GBASE-T MDI/MDI-X */
325  if (ecmd->port == PORT_TP
326  && (ethtool_cmd_speed(ecmd) == SPEED_10000)) {
327  switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
330  ecmd->eth_tp_mdix = ETH_TP_MDI;
331  break;
332  case 0:
333  ecmd->eth_tp_mdix = ETH_TP_MDI_X;
334  break;
335  default:
336  /* It's complicated... */
338  break;
339  }
340  }
341 }
343 
353  const struct ethtool_pauseparam *ecmd)
354 {
355  int adv, old_adv;
356 
357  WARN_ON(!(mdio->mmds & MDIO_DEVS_AN));
358 
359  old_adv = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
361  adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
362  mii_advertise_flowctrl((ecmd->rx_pause ? FLOW_CTRL_RX : 0) |
363  (ecmd->tx_pause ? FLOW_CTRL_TX : 0)));
364  if (adv != old_adv) {
365  mdio->mdio_write(mdio->dev, mdio->prtad, MDIO_MMD_AN,
366  MDIO_AN_ADVERTISE, adv);
367  mdio45_nway_restart(mdio);
368  }
369 }
371 
380 int mdio_mii_ioctl(const struct mdio_if_info *mdio,
381  struct mii_ioctl_data *mii_data, int cmd)
382 {
383  int prtad, devad;
384  u16 addr = mii_data->reg_num;
385 
386  /* Validate/convert cmd to one of SIOC{G,S}MIIREG */
387  switch (cmd) {
388  case SIOCGMIIPHY:
389  if (mdio->prtad == MDIO_PRTAD_NONE)
390  return -EOPNOTSUPP;
391  mii_data->phy_id = mdio->prtad;
392  cmd = SIOCGMIIREG;
393  break;
394  case SIOCGMIIREG:
395  case SIOCSMIIREG:
396  break;
397  default:
398  return -EOPNOTSUPP;
399  }
400 
401  /* Validate/convert phy_id */
402  if ((mdio->mode_support & MDIO_SUPPORTS_C45) &&
403  mdio_phy_id_is_c45(mii_data->phy_id)) {
404  prtad = mdio_phy_id_prtad(mii_data->phy_id);
405  devad = mdio_phy_id_devad(mii_data->phy_id);
406  } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) &&
407  mii_data->phy_id < 0x20) {
408  prtad = mii_data->phy_id;
409  devad = MDIO_DEVAD_NONE;
410  addr &= 0x1f;
411  } else if ((mdio->mode_support & MDIO_EMULATE_C22) &&
412  mdio->prtad != MDIO_PRTAD_NONE &&
413  mii_data->phy_id == mdio->prtad) {
414  /* Remap commonly-used MII registers. */
415  prtad = mdio->prtad;
416  switch (addr) {
417  case MII_BMCR:
418  case MII_BMSR:
419  case MII_PHYSID1:
420  case MII_PHYSID2:
421  devad = __ffs(mdio->mmds);
422  break;
423  case MII_ADVERTISE:
424  case MII_LPA:
425  if (!(mdio->mmds & MDIO_DEVS_AN))
426  return -EINVAL;
427  devad = MDIO_MMD_AN;
428  if (addr == MII_ADVERTISE)
429  addr = MDIO_AN_ADVERTISE;
430  else
431  addr = MDIO_AN_LPA;
432  break;
433  default:
434  return -EINVAL;
435  }
436  } else {
437  return -EINVAL;
438  }
439 
440  if (cmd == SIOCGMIIREG) {
441  int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr);
442  if (rc < 0)
443  return rc;
444  mii_data->val_out = rc;
445  return 0;
446  } else {
447  return mdio->mdio_write(mdio->dev, prtad, devad, addr,
448  mii_data->val_in);
449  }
450 }