Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mii.c
Go to the documentation of this file.
1 /*
2 
3  mii.c: MII interface library
4 
5  Maintained by Jeff Garzik <[email protected]>
6  Copyright 2001,2002 Jeff Garzik
7 
8  Various code came from myson803.c and other files by
9  Donald Becker. Copyright:
10 
11  Written 1998-2002 by Donald Becker.
12 
13  This software may be used and distributed according
14  to the terms of the GNU General Public License (GPL),
15  incorporated herein by reference. Drivers based on
16  or derived from this code fall under the GPL and must
17  retain the authorship, copyright and license notice.
18  This file is not a complete program and may only be
19  used when the entire operating system is licensed
20  under the GPL.
21 
22  The author may be reached as [email protected], or C/O
23  Scyld Computing Corporation
24  410 Severn Ave., Suite 210
25  Annapolis MD 21403
26 
27 
28  */
29 
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/netdevice.h>
33 #include <linux/ethtool.h>
34 #include <linux/mii.h>
35 
36 static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
37 {
38  int advert;
39 
40  advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
41 
42  return mii_lpa_to_ethtool_lpa_t(advert);
43 }
44 
55 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
56 {
57  struct net_device *dev = mii->dev;
58  u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
59  u32 nego;
60 
61  ecmd->supported =
65  if (mii->supports_gmii)
68 
69  /* only supports twisted-pair */
70  ecmd->port = PORT_MII;
71 
72  /* only supports internal transceiver */
73  ecmd->transceiver = XCVR_INTERNAL;
74 
75  /* this isn't fully supported at higher layers */
76  ecmd->phy_address = mii->phy_id;
78 
80 
81  bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
82  bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
83  if (mii->supports_gmii) {
84  ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
85  stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
86  }
87  if (bmcr & BMCR_ANENABLE) {
89  ecmd->autoneg = AUTONEG_ENABLE;
90 
91  ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
92  if (mii->supports_gmii)
93  ecmd->advertising |=
94  mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
95 
96  if (bmsr & BMSR_ANEGCOMPLETE) {
97  ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
98  ecmd->lp_advertising |=
99  mii_stat1000_to_ethtool_lpa_t(stat1000);
100  } else {
101  ecmd->lp_advertising = 0;
102  }
103 
104  nego = ecmd->advertising & ecmd->lp_advertising;
105 
106  if (nego & (ADVERTISED_1000baseT_Full |
108  ethtool_cmd_speed_set(ecmd, SPEED_1000);
109  ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
110  } else if (nego & (ADVERTISED_100baseT_Full |
112  ethtool_cmd_speed_set(ecmd, SPEED_100);
113  ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
114  } else {
115  ethtool_cmd_speed_set(ecmd, SPEED_10);
116  ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
117  }
118  } else {
119  ecmd->autoneg = AUTONEG_DISABLE;
120 
121  ethtool_cmd_speed_set(ecmd,
122  ((bmcr & BMCR_SPEED1000 &&
123  (bmcr & BMCR_SPEED100) == 0) ?
124  SPEED_1000 :
125  ((bmcr & BMCR_SPEED100) ?
126  SPEED_100 : SPEED_10)));
127  ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
128  }
129 
130  mii->full_duplex = ecmd->duplex;
131 
132  /* ignore maxtxpkt, maxrxpkt for now */
133 
134  return 0;
135 }
136 
144 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
145 {
146  struct net_device *dev = mii->dev;
147  u32 speed = ethtool_cmd_speed(ecmd);
148 
149  if (speed != SPEED_10 &&
150  speed != SPEED_100 &&
151  speed != SPEED_1000)
152  return -EINVAL;
153  if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
154  return -EINVAL;
155  if (ecmd->port != PORT_MII)
156  return -EINVAL;
157  if (ecmd->transceiver != XCVR_INTERNAL)
158  return -EINVAL;
159  if (ecmd->phy_address != mii->phy_id)
160  return -EINVAL;
161  if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
162  return -EINVAL;
163  if ((speed == SPEED_1000) && (!mii->supports_gmii))
164  return -EINVAL;
165 
166  /* ignore supported, maxtxpkt, maxrxpkt */
167 
168  if (ecmd->autoneg == AUTONEG_ENABLE) {
169  u32 bmcr, advert, tmp;
170  u32 advert2 = 0, tmp2 = 0;
171 
172  if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
178  return -EINVAL;
179 
180  /* advertise only what has been requested */
181  advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
182  tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
183  if (mii->supports_gmii) {
184  advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
185  tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
186  }
187  tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
188 
189  if (mii->supports_gmii)
190  tmp2 |=
191  ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
192  if (advert != tmp) {
193  mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
194  mii->advertising = tmp;
195  }
196  if ((mii->supports_gmii) && (advert2 != tmp2))
197  mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
198 
199  /* turn on autonegotiation, and force a renegotiate */
200  bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
201  bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
202  mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
203 
204  mii->force_media = 0;
205  } else {
206  u32 bmcr, tmp;
207 
208  /* turn off auto negotiation, set speed and duplexity */
209  bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
210  tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
212  if (speed == SPEED_1000)
213  tmp |= BMCR_SPEED1000;
214  else if (speed == SPEED_100)
215  tmp |= BMCR_SPEED100;
216  if (ecmd->duplex == DUPLEX_FULL) {
217  tmp |= BMCR_FULLDPLX;
218  mii->full_duplex = 1;
219  } else
220  mii->full_duplex = 0;
221  if (bmcr != tmp)
222  mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
223 
224  mii->force_media = 1;
225  }
226  return 0;
227 }
228 
234 {
235  int reg;
236 
237  reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
238  if (reg & BMSR_ESTATEN) {
239  reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
241  return 1;
242  }
243 
244  return 0;
245 }
246 
253 int mii_link_ok (struct mii_if_info *mii)
254 {
255  /* first, a dummy read, needed to latch some MII phys */
256  mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
257  if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
258  return 1;
259  return 0;
260 }
261 
268 int mii_nway_restart (struct mii_if_info *mii)
269 {
270  int bmcr;
271  int r = -EINVAL;
272 
273  /* if autoneg is off, it's an error */
274  bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
275 
276  if (bmcr & BMCR_ANENABLE) {
277  bmcr |= BMCR_ANRESTART;
278  mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
279  r = 0;
280  }
281 
282  return r;
283 }
284 
293 void mii_check_link (struct mii_if_info *mii)
294 {
295  int cur_link = mii_link_ok(mii);
296  int prev_link = netif_carrier_ok(mii->dev);
297 
298  if (cur_link && !prev_link)
299  netif_carrier_on(mii->dev);
300  else if (prev_link && !cur_link)
301  netif_carrier_off(mii->dev);
302 }
303 
313 unsigned int mii_check_media (struct mii_if_info *mii,
314  unsigned int ok_to_print,
315  unsigned int init_media)
316 {
317  unsigned int old_carrier, new_carrier;
318  int advertise, lpa, media, duplex;
319  int lpa2 = 0;
320 
321  /* if forced media, go no further */
322  if (mii->force_media)
323  return 0; /* duplex did not change */
324 
325  /* check current and old link status */
326  old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
327  new_carrier = (unsigned int) mii_link_ok(mii);
328 
329  /* if carrier state did not change, this is a "bounce",
330  * just exit as everything is already set correctly
331  */
332  if ((!init_media) && (old_carrier == new_carrier))
333  return 0; /* duplex did not change */
334 
335  /* no carrier, nothing much to do */
336  if (!new_carrier) {
337  netif_carrier_off(mii->dev);
338  if (ok_to_print)
339  netdev_info(mii->dev, "link down\n");
340  return 0; /* duplex did not change */
341  }
342 
343  /*
344  * we have carrier, see who's on the other end
345  */
346  netif_carrier_on(mii->dev);
347 
348  /* get MII advertise and LPA values */
349  if ((!init_media) && (mii->advertising))
350  advertise = mii->advertising;
351  else {
352  advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
353  mii->advertising = advertise;
354  }
355  lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
356  if (mii->supports_gmii)
357  lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
358 
359  /* figure out media and duplex from advertise and LPA values */
360  media = mii_nway_result(lpa & advertise);
361  duplex = (media & ADVERTISE_FULL) ? 1 : 0;
362  if (lpa2 & LPA_1000FULL)
363  duplex = 1;
364 
365  if (ok_to_print)
366  netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
367  lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
369  100 : 10,
370  duplex ? "full" : "half",
371  lpa);
372 
373  if ((init_media) || (mii->full_duplex != duplex)) {
374  mii->full_duplex = duplex;
375  return 1; /* duplex changed */
376  }
377 
378  return 0; /* duplex did not change */
379 }
380 
391 int generic_mii_ioctl(struct mii_if_info *mii_if,
392  struct mii_ioctl_data *mii_data, int cmd,
393  unsigned int *duplex_chg_out)
394 {
395  int rc = 0;
396  unsigned int duplex_changed = 0;
397 
398  if (duplex_chg_out)
399  *duplex_chg_out = 0;
400 
401  mii_data->phy_id &= mii_if->phy_id_mask;
402  mii_data->reg_num &= mii_if->reg_num_mask;
403 
404  switch(cmd) {
405  case SIOCGMIIPHY:
406  mii_data->phy_id = mii_if->phy_id;
407  /* fall through */
408 
409  case SIOCGMIIREG:
410  mii_data->val_out =
411  mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
412  mii_data->reg_num);
413  break;
414 
415  case SIOCSMIIREG: {
416  u16 val = mii_data->val_in;
417 
418  if (mii_data->phy_id == mii_if->phy_id) {
419  switch(mii_data->reg_num) {
420  case MII_BMCR: {
421  unsigned int new_duplex = 0;
422  if (val & (BMCR_RESET|BMCR_ANENABLE))
423  mii_if->force_media = 0;
424  else
425  mii_if->force_media = 1;
426  if (mii_if->force_media &&
427  (val & BMCR_FULLDPLX))
428  new_duplex = 1;
429  if (mii_if->full_duplex != new_duplex) {
430  duplex_changed = 1;
431  mii_if->full_duplex = new_duplex;
432  }
433  break;
434  }
435  case MII_ADVERTISE:
436  mii_if->advertising = val;
437  break;
438  default:
439  /* do nothing */
440  break;
441  }
442  }
443 
444  mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
445  mii_data->reg_num, val);
446  break;
447  }
448 
449  default:
450  rc = -EOPNOTSUPP;
451  break;
452  }
453 
454  if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
455  *duplex_chg_out = 1;
456 
457  return rc;
458 }
459 
460 MODULE_AUTHOR ("Jeff Garzik <[email protected]>");
461 MODULE_DESCRIPTION ("MII hardware support library");
462 MODULE_LICENSE("GPL");
463 
472