Browse Source

[ethernet] Add MII link status functions from Linux

Signed-off-by: Michael Brown <mcb30@etherboot.org>
tags/v0.9.8
Daniel Verkamp 16 years ago
parent
commit
1f80b2dcd5
2 changed files with 206 additions and 0 deletions
  1. 59
    0
      src/include/mii.h
  2. 147
    0
      src/net/mii.c

+ 59
- 0
src/include/mii.h View File

@@ -157,4 +157,63 @@ struct mii_if_info {
157 157
         void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
158 158
 };
159 159
 
160
+
161
+extern int mii_link_ok (struct mii_if_info *mii);
162
+extern void mii_check_link (struct mii_if_info *mii);
163
+extern unsigned int mii_check_media (struct mii_if_info *mii,
164
+                                       unsigned int ok_to_print,
165
+                                       unsigned int init_media);
166
+
167
+
168
+/**
169
+ * mii_nway_result
170
+ * @negotiated: value of MII ANAR and'd with ANLPAR
171
+ *
172
+ * Given a set of MII abilities, check each bit and returns the
173
+ * currently supported media, in the priority order defined by
174
+ * IEEE 802.3u.  We use LPA_xxx constants but note this is not the
175
+ * value of LPA solely, as described above.
176
+ *
177
+ * The one exception to IEEE 802.3u is that 100baseT4 is placed
178
+ * between 100T-full and 100T-half.  If your phy does not support
179
+ * 100T4 this is fine.  If your phy places 100T4 elsewhere in the
180
+ * priority order, you will need to roll your own function.
181
+ */
182
+static inline unsigned int mii_nway_result (unsigned int negotiated)
183
+{
184
+        unsigned int ret;
185
+
186
+        if (negotiated & LPA_100FULL)
187
+                ret = LPA_100FULL;
188
+        else if (negotiated & LPA_100BASE4)
189
+                ret = LPA_100BASE4;
190
+        else if (negotiated & LPA_100HALF)
191
+                ret = LPA_100HALF;
192
+        else if (negotiated & LPA_10FULL)
193
+                ret = LPA_10FULL;
194
+        else
195
+                ret = LPA_10HALF;
196
+
197
+        return ret;
198
+}
199
+
200
+/**
201
+ * mii_duplex
202
+ * @duplex_lock: Non-zero if duplex is locked at full
203
+ * @negotiated: value of MII ANAR and'd with ANLPAR
204
+ *
205
+ * A small helper function for a common case.  Returns one
206
+ * if the media is operating or locked at full duplex, and
207
+ * returns zero otherwise.
208
+ */
209
+static inline unsigned int mii_duplex (unsigned int duplex_lock,
210
+                                       unsigned int negotiated)
211
+{
212
+        if (duplex_lock)
213
+                return 1;
214
+        if (mii_nway_result(negotiated) & LPA_DUPLEX)
215
+                return 1;
216
+        return 0;
217
+}
218
+
160 219
 #endif

+ 147
- 0
src/net/mii.c View File

@@ -0,0 +1,147 @@
1
+/*
2
+
3
+	mii.c: MII interface library
4
+
5
+	Ported to gPXE by Daniel Verkamp <daniel@drv.nu>
6
+	from Linux drivers/net/mii.c
7
+
8
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
9
+	Copyright 2001,2002 Jeff Garzik
10
+
11
+	Various code came from myson803.c and other files by
12
+	Donald Becker.  Copyright:
13
+
14
+		Written 1998-2002 by Donald Becker.
15
+
16
+		This software may be used and distributed according
17
+		to the terms of the GNU General Public License (GPL),
18
+		incorporated herein by reference.  Drivers based on
19
+		or derived from this code fall under the GPL and must
20
+		retain the authorship, copyright and license notice.
21
+		This file is not a complete program and may only be
22
+		used when the entire operating system is licensed
23
+		under the GPL.
24
+
25
+		The author may be reached as becker@scyld.com, or C/O
26
+		Scyld Computing Corporation
27
+		410 Severn Ave., Suite 210
28
+		Annapolis MD 21403
29
+
30
+*/
31
+
32
+#include <mii.h>
33
+
34
+/**
35
+ * mii_link_ok - is link status up/ok
36
+ * @mii: the MII interface
37
+ *
38
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
39
+ */
40
+int
41
+mii_link_ok ( struct mii_if_info *mii )
42
+{
43
+	/* first, a dummy read, needed to latch some MII phys */
44
+	mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR );
45
+	if ( mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ) & BMSR_LSTATUS )
46
+		return 1;
47
+	return 0;
48
+}
49
+
50
+/**
51
+ * mii_check_link - check MII link status
52
+ * @mii: MII interface
53
+ *
54
+ * If the link status changed (previous != current), call
55
+ * netif_carrier_on() if current link status is Up or call
56
+ * netif_carrier_off() if current link status is Down.
57
+ */
58
+void
59
+mii_check_link ( struct mii_if_info *mii )
60
+{
61
+	int cur_link = mii_link_ok ( mii );
62
+	int prev_link = netdev_link_ok ( mii->dev );
63
+
64
+	if ( cur_link && !prev_link )
65
+		netdev_link_up ( mii->dev );
66
+	else if (prev_link && !cur_link)
67
+		netdev_link_down ( mii->dev );
68
+}
69
+
70
+
71
+/**
72
+ * mii_check_media - check the MII interface for a duplex change
73
+ * @mii: the MII interface
74
+ * @ok_to_print: OK to print link up/down messages
75
+ * @init_media: OK to save duplex mode in @mii
76
+ *
77
+ * Returns 1 if the duplex mode changed, 0 if not.
78
+ * If the media type is forced, always returns 0.
79
+ */
80
+unsigned int
81
+mii_check_media ( struct mii_if_info *mii,
82
+                  unsigned int ok_to_print,
83
+                  unsigned int init_media )
84
+{
85
+	unsigned int old_carrier, new_carrier;
86
+	int advertise, lpa, media, duplex;
87
+	int lpa2 = 0;
88
+
89
+	/* if forced media, go no further */
90
+	if (mii->force_media)
91
+		return 0; /* duplex did not change */
92
+
93
+	/* check current and old link status */
94
+	old_carrier = netdev_link_ok ( mii->dev ) ? 1 : 0;
95
+	new_carrier = (unsigned int) mii_link_ok ( mii );
96
+
97
+	/* if carrier state did not change, this is a "bounce",
98
+	 * just exit as everything is already set correctly
99
+	 */
100
+	if ( ( ! init_media ) && ( old_carrier == new_carrier ) )
101
+		return 0; /* duplex did not change */
102
+
103
+	/* no carrier, nothing much to do */
104
+	if ( ! new_carrier ) {
105
+		netdev_link_down ( mii->dev );
106
+		if ( ok_to_print )
107
+			DBG ( "%s: link down\n", mii->dev->name);
108
+		return 0; /* duplex did not change */
109
+	}
110
+
111
+	/*
112
+	 * we have carrier, see who's on the other end
113
+	 */
114
+	netdev_link_up ( mii->dev );
115
+
116
+	/* get MII advertise and LPA values */
117
+	if ( ( ! init_media ) && ( mii->advertising ) ) {
118
+		advertise = mii->advertising;
119
+	} else {
120
+		advertise = mii->mdio_read ( mii->dev, mii->phy_id, MII_ADVERTISE );
121
+		mii->advertising = advertise;
122
+	}
123
+	lpa = mii->mdio_read ( mii->dev, mii->phy_id, MII_LPA );
124
+	if ( mii->supports_gmii )
125
+		lpa2 = mii->mdio_read ( mii->dev, mii->phy_id, MII_STAT1000 );
126
+
127
+	/* figure out media and duplex from advertise and LPA values */
128
+	media = mii_nway_result ( lpa & advertise );
129
+	duplex = ( media & ADVERTISE_FULL ) ? 1 : 0;
130
+	if ( lpa2 & LPA_1000FULL )
131
+		duplex = 1;
132
+
133
+	if ( ok_to_print )
134
+		DBG ( "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
135
+		       mii->dev->name,
136
+		       lpa2 & ( LPA_1000FULL | LPA_1000HALF ) ? "1000" :
137
+		       media & ( ADVERTISE_100FULL | ADVERTISE_100HALF ) ? "100" : "10",
138
+		       duplex ? "full" : "half",
139
+		       lpa);
140
+
141
+	if ( ( init_media ) || ( mii->full_duplex != duplex ) ) {
142
+		mii->full_duplex = duplex;
143
+		return 1; /* duplex changed */
144
+	}
145
+
146
+	return 0; /* duplex did not change */
147
+}

Loading…
Cancel
Save