]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/dev/mii/mii_physubr.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / dev / mii / mii_physubr.c
1 /*      $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */
2
3 /*-
4  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 /*
37  * Subroutines common to all PHYs.
38  */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/errno.h>
45 #include <sys/module.h>
46 #include <sys/bus.h>
47
48 #include <net/if.h>
49 #include <net/if_media.h>
50
51 #include <dev/mii/mii.h>
52 #include <dev/mii/miivar.h>
53
54 #include "miibus_if.h"
55
56 /*
57  * Media to register setting conversion table.  Order matters.
58  */
59 const struct mii_media mii_media_table[MII_NMEDIA] = {
60         /* None */
61         { BMCR_ISO,             ANAR_CSMA,
62           0, },
63
64         /* 10baseT */
65         { BMCR_S10,             ANAR_CSMA|ANAR_10,
66           0, },
67
68         /* 10baseT-FDX */
69         { BMCR_S10|BMCR_FDX,    ANAR_CSMA|ANAR_10_FD,
70           0, },
71
72         /* 100baseT4 */
73         { BMCR_S100,            ANAR_CSMA|ANAR_T4,
74           0, },
75
76         /* 100baseTX */
77         { BMCR_S100,            ANAR_CSMA|ANAR_TX,
78           0, },
79
80         /* 100baseTX-FDX */
81         { BMCR_S100|BMCR_FDX,   ANAR_CSMA|ANAR_TX_FD,
82           0, },
83
84         /* 1000baseX */
85         { BMCR_S1000,           ANAR_CSMA,
86           0, },
87
88         /* 1000baseX-FDX */
89         { BMCR_S1000|BMCR_FDX,  ANAR_CSMA,
90           0, },
91
92         /* 1000baseT */
93         { BMCR_S1000,           ANAR_CSMA,
94           GTCR_ADV_1000THDX },
95
96         /* 1000baseT-FDX */
97         { BMCR_S1000,           ANAR_CSMA,
98           GTCR_ADV_1000TFDX },
99 };
100
101 void
102 mii_phy_setmedia(struct mii_softc *sc)
103 {
104         struct mii_data *mii = sc->mii_pdata;
105         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
106         int bmcr, anar, gtcr;
107
108         if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
109                 /*
110                  * Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG.
111                  * The former is necessary as we might switch from flow-
112                  * control advertisment being off to on or vice versa.
113                  */
114                 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 ||
115                     (sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0)
116                         (void)mii_phy_auto(sc);
117                 return;
118         }
119
120         /*
121          * Table index is stored in the media entry.
122          */
123
124         KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
125             ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
126             ife->ifm_data));
127
128         anar = mii_media_table[ife->ifm_data].mm_anar;
129         bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
130         gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
131
132         if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
133                 gtcr |= GTCR_MAN_MS;
134                 if ((ife->ifm_media & IFM_ETH_MASTER) != 0)
135                         gtcr |= GTCR_ADV_MS;
136         }
137
138         if ((ife->ifm_media & IFM_GMASK) == (IFM_FDX | IFM_FLOW) ||
139             (sc->mii_flags & MIIF_FORCEPAUSE) != 0) {
140                 if ((sc->mii_flags & MIIF_IS_1000X) != 0)
141                         anar |= ANAR_X_PAUSE_TOWARDS;
142                 else {
143                         anar |= ANAR_FC;
144                         /* XXX Only 1000BASE-T has PAUSE_ASYM? */
145                         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0 &&
146                             (sc->mii_extcapabilities &
147                             (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0)
148                                 anar |= ANAR_X_PAUSE_ASYM;
149                 }
150         }
151
152         if ((ife->ifm_media & IFM_LOOP) != 0)
153                 bmcr |= BMCR_LOOP;
154
155         PHY_WRITE(sc, MII_ANAR, anar);
156         PHY_WRITE(sc, MII_BMCR, bmcr);
157         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0)
158                 PHY_WRITE(sc, MII_100T2CR, gtcr);
159 }
160
161 int
162 mii_phy_auto(struct mii_softc *sc)
163 {
164         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
165         int anar, gtcr;
166
167         /*
168          * Check for 1000BASE-X.  Autonegotiation is a bit
169          * different on such devices.
170          */
171         if ((sc->mii_flags & MIIF_IS_1000X) != 0) {
172                 anar = 0;
173                 if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0)
174                         anar |= ANAR_X_FD;
175                 if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0)
176                         anar |= ANAR_X_HD;
177
178                 if ((ife->ifm_media & IFM_FLOW) != 0 ||
179                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
180                         anar |= ANAR_X_PAUSE_TOWARDS;
181                 PHY_WRITE(sc, MII_ANAR, anar);
182         } else {
183                 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
184                     ANAR_CSMA;
185                 if ((ife->ifm_media & IFM_FLOW) != 0 ||
186                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0) {
187                         if ((sc->mii_capabilities & BMSR_100TXFDX) != 0)
188                                 anar |= ANAR_FC;
189                         /* XXX Only 1000BASE-T has PAUSE_ASYM? */
190                         if (((sc->mii_flags & MIIF_HAVE_GTCR) != 0) &&
191                             (sc->mii_extcapabilities &
192                             (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0)
193                                 anar |= ANAR_X_PAUSE_ASYM;
194                 }
195                 PHY_WRITE(sc, MII_ANAR, anar);
196                 if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
197                         gtcr = 0;
198                         if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0)
199                                 gtcr |= GTCR_ADV_1000TFDX;
200                         if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0)
201                                 gtcr |= GTCR_ADV_1000THDX;
202                         PHY_WRITE(sc, MII_100T2CR, gtcr);
203                 }
204         }
205         PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
206         return (EJUSTRETURN);
207 }
208
209 int
210 mii_phy_tick(struct mii_softc *sc)
211 {
212         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
213         struct ifnet *ifp = sc->mii_pdata->mii_ifp;
214         int reg;
215
216         /* Just bail now if the interface is down. */
217         if ((ifp->if_flags & IFF_UP) == 0)
218                 return (EJUSTRETURN);
219
220         /*
221          * If we're not doing autonegotiation, we don't need to do
222          * any extra work here.  However, we need to check the link
223          * status so we can generate an announcement if the status
224          * changes.
225          */
226         if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
227                 sc->mii_ticks = 0;      /* reset autonegotiation timer. */
228                 return (0);
229         }
230
231         /* Read the status register twice; BMSR_LINK is latch-low. */
232         reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
233         if ((reg & BMSR_LINK) != 0) {
234                 sc->mii_ticks = 0;      /* reset autonegotiation timer. */
235                 /* See above. */
236                 return (0);
237         }
238
239         /* Announce link loss right after it happens */
240         if (sc->mii_ticks++ == 0)
241                 return (0);
242
243         /* XXX: use default value if phy driver did not set mii_anegticks */
244         if (sc->mii_anegticks == 0)
245                 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
246
247         /* Only retry autonegotiation every mii_anegticks ticks. */
248         if (sc->mii_ticks <= sc->mii_anegticks)
249                 return (EJUSTRETURN);
250
251         sc->mii_ticks = 0;
252         mii_phy_reset(sc);
253         mii_phy_auto(sc);
254         return (0);
255 }
256
257 void
258 mii_phy_reset(struct mii_softc *sc)
259 {
260         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
261         int reg, i;
262
263         if ((sc->mii_flags & MIIF_NOISOLATE) != 0)
264                 reg = BMCR_RESET;
265         else
266                 reg = BMCR_RESET | BMCR_ISO;
267         PHY_WRITE(sc, MII_BMCR, reg);
268
269         /* Wait 100ms for it to complete. */
270         for (i = 0; i < 100; i++) {
271                 reg = PHY_READ(sc, MII_BMCR);
272                 if ((reg & BMCR_RESET) == 0)
273                         break;
274                 DELAY(1000);
275         }
276
277         if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
278                 if ((ife == NULL && sc->mii_inst != 0) ||
279                     (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst))
280                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
281         }
282 }
283
284 void
285 mii_phy_down(struct mii_softc *sc)
286 {
287
288 }
289
290 void
291 mii_phy_update(struct mii_softc *sc, int cmd)
292 {
293         struct mii_data *mii = sc->mii_pdata;
294
295         if (sc->mii_media_active != mii->mii_media_active ||
296             cmd == MII_MEDIACHG) {
297                 MIIBUS_STATCHG(sc->mii_dev);
298                 sc->mii_media_active = mii->mii_media_active;
299         }
300         if (sc->mii_media_status != mii->mii_media_status) {
301                 MIIBUS_LINKCHG(sc->mii_dev);
302                 sc->mii_media_status = mii->mii_media_status;
303         }
304 }
305
306 /*
307  * Given an ifmedia word, return the corresponding ANAR value.
308  */
309 int
310 mii_anar(int media)
311 {
312         int rv;
313
314         switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
315         case IFM_ETHER|IFM_10_T:
316                 rv = ANAR_10|ANAR_CSMA;
317                 break;
318         case IFM_ETHER|IFM_10_T|IFM_FDX:
319                 rv = ANAR_10_FD|ANAR_CSMA;
320                 break;
321         case IFM_ETHER|IFM_100_TX:
322                 rv = ANAR_TX|ANAR_CSMA;
323                 break;
324         case IFM_ETHER|IFM_100_TX|IFM_FDX:
325                 rv = ANAR_TX_FD|ANAR_CSMA;
326                 break;
327         case IFM_ETHER|IFM_100_T4:
328                 rv = ANAR_T4|ANAR_CSMA;
329                 break;
330         default:
331                 rv = 0;
332                 break;
333         }
334
335         return (rv);
336 }
337
338 /*
339  * Initialize generic PHY media based on BMSR, called when a PHY is
340  * attached.  We expect to be set up to print a comma-separated list
341  * of media names.  Does not print a newline.
342  */
343 void
344 mii_add_media(struct mii_softc *sc)
345 {
346         struct mii_data *mii = sc->mii_pdata;
347         const char *sep = "";
348
349         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) {
350                 printf("no media present");
351                 return;
352         }
353
354 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
355 #define PRINT(s)        printf("%s%s", sep, s); sep = ", "
356
357         if (sc->mii_capabilities & BMSR_10THDX) {
358                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0);
359                 PRINT("10baseT");
360         }
361         if (sc->mii_capabilities & BMSR_10TFDX) {
362                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
363                     BMCR_FDX);
364                 PRINT("10baseT-FDX");
365         }
366         if (sc->mii_capabilities & BMSR_100TXHDX) {
367                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
368                     BMCR_S100);
369                 PRINT("100baseTX");
370         }
371         if (sc->mii_capabilities & BMSR_100TXFDX) {
372                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
373                     BMCR_S100|BMCR_FDX);
374                 PRINT("100baseTX-FDX");
375         }
376         if (sc->mii_capabilities & BMSR_100T4) {
377                 /*
378                  * XXX How do you enable 100baseT4?  I assume we set
379                  * XXX BMCR_S100 and then assume the PHYs will take
380                  * XXX watever action is necessary to switch themselves
381                  * XXX into T4 mode.
382                  */
383                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
384                     BMCR_S100);
385                 PRINT("100baseT4");
386         }
387         if (sc->mii_capabilities & BMSR_ANEG) {
388                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
389                     BMCR_AUTOEN);
390                 PRINT("auto");
391         }
392
393
394
395 #undef ADD
396 #undef PRINT
397 }
398
399 /*
400  * Initialize generic PHY media based on BMSR, called when a PHY is
401  * attached.  We expect to be set up to print a comma-separated list
402  * of media names.  Does not print a newline.
403  */
404 void
405 mii_phy_add_media(struct mii_softc *sc)
406 {
407         struct mii_data *mii = sc->mii_pdata;
408         const char *sep = "";
409         int fdx = 0;
410
411         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
412             (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) {
413                 printf("no media present");
414                 return;
415         }
416
417         /*
418          * Set the autonegotiation timer for 10/100 media.  Gigabit media is
419          * handled below.
420          */
421         sc->mii_anegticks = MII_ANEGTICKS;
422
423 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
424 #define PRINT(s)        printf("%s%s", sep, s); sep = ", "
425
426         if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
427                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
428                     MII_MEDIA_NONE);
429
430         /*
431          * There are different interpretations for the bits in
432          * HomePNA PHYs.  And there is really only one media type
433          * that is supported.
434          */
435         if ((sc->mii_flags & MIIF_IS_HPNA) != 0) {
436                 if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
437                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
438                             sc->mii_inst), MII_MEDIA_10_T);
439                         PRINT("HomePNA1");
440                 }
441                 return;
442         }
443
444         if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
445                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
446                     MII_MEDIA_10_T);
447                 PRINT("10baseT");
448         }
449         if ((sc->mii_capabilities & BMSR_10TFDX) != 0) {
450                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
451                     MII_MEDIA_10_T_FDX);
452                 PRINT("10baseT-FDX");
453                 if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
454                     (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
455                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T,
456                             IFM_FDX | IFM_FLOW, sc->mii_inst),
457                             MII_MEDIA_10_T_FDX);
458                         PRINT("10baseT-FDX-flow");
459                 }
460                 fdx = 1;
461         }
462         if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) {
463                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
464                     MII_MEDIA_100_TX);
465                 PRINT("100baseTX");
466         }
467         if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) {
468                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
469                     MII_MEDIA_100_TX_FDX);
470                 PRINT("100baseTX-FDX");
471                 if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
472                     (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
473                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX,
474                             IFM_FDX | IFM_FLOW, sc->mii_inst),
475                             MII_MEDIA_100_TX_FDX);
476                         PRINT("100baseTX-FDX-flow");
477                 }
478                 fdx = 1;
479         }
480         if ((sc->mii_capabilities & BMSR_100T4) != 0) {
481                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
482                     MII_MEDIA_100_T4);
483                 PRINT("100baseT4");
484         }
485
486         if ((sc->mii_extcapabilities & EXTSR_MEDIAMASK) != 0) {
487                 /*
488                  * XXX Right now only handle 1000SX and 1000TX.  Need
489                  * XXX to handle 1000LX and 1000CX somehow.
490                  */
491                 if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0) {
492                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
493                         sc->mii_flags |= MIIF_IS_1000X;
494                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
495                             sc->mii_inst), MII_MEDIA_1000_X);
496                         PRINT("1000baseSX");
497                 }
498                 if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) {
499                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
500                         sc->mii_flags |= MIIF_IS_1000X;
501                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
502                             sc->mii_inst), MII_MEDIA_1000_X_FDX);
503                         PRINT("1000baseSX-FDX");
504                         if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
505                             (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
506                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX,
507                                     IFM_FDX | IFM_FLOW, sc->mii_inst),
508                                     MII_MEDIA_1000_X_FDX);
509                                 PRINT("1000baseSX-FDX-flow");
510                         }
511                         fdx = 1;
512                 }
513
514                 /*
515                  * 1000baseT media needs to be able to manipulate
516                  * master/slave mode.
517                  *
518                  * All 1000baseT PHYs have a 1000baseT control register.
519                  */
520                 if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) {
521                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
522                         sc->mii_flags |= MIIF_HAVE_GTCR;
523                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
524                             sc->mii_inst), MII_MEDIA_1000_T);
525                         PRINT("1000baseT");
526                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
527                             IFM_ETH_MASTER, sc->mii_inst), MII_MEDIA_1000_T);
528                         PRINT("1000baseT-master");
529                 }
530                 if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) {
531                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
532                         sc->mii_flags |= MIIF_HAVE_GTCR;
533                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
534                             sc->mii_inst), MII_MEDIA_1000_T_FDX);
535                         PRINT("1000baseT-FDX");
536                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
537                             IFM_FDX | IFM_ETH_MASTER, sc->mii_inst),
538                             MII_MEDIA_1000_T_FDX);
539                         PRINT("1000baseT-FDX-master");
540                         if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
541                             (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
542                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
543                                     IFM_FDX | IFM_FLOW, sc->mii_inst),
544                                     MII_MEDIA_1000_T_FDX);
545                                 PRINT("1000baseT-FDX-flow");
546                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
547                                     IFM_FDX | IFM_FLOW | IFM_ETH_MASTER,
548                                     sc->mii_inst), MII_MEDIA_1000_T_FDX);
549                                 PRINT("1000baseT-FDX-flow-master");
550                         }
551                         fdx = 1;
552                 }
553         }
554
555         if ((sc->mii_capabilities & BMSR_ANEG) != 0) {
556                 /* intentionally invalid index */
557                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
558                     MII_NMEDIA);
559                 PRINT("auto");
560                 if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) {
561                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW,
562                             sc->mii_inst), MII_NMEDIA);
563                         PRINT("auto-flow");
564                 }
565         }
566 #undef ADD
567 #undef PRINT
568 }
569
570 int
571 mii_phy_detach(device_t dev)
572 {
573         struct mii_softc *sc;
574
575         sc = device_get_softc(dev);
576         mii_phy_down(sc);
577         sc->mii_dev = NULL;
578         LIST_REMOVE(sc, mii_list);
579         return (0);
580 }
581
582 const struct mii_phydesc *
583 mii_phy_match_gen(const struct mii_attach_args *ma,
584   const struct mii_phydesc *mpd, size_t len)
585 {
586
587         for (; mpd->mpd_name != NULL;
588             mpd = (const struct mii_phydesc *)((const char *)mpd + len)) {
589                 if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
590                     MII_MODEL(ma->mii_id2) == mpd->mpd_model)
591                         return (mpd);
592         }
593         return (NULL);
594 }
595
596 const struct mii_phydesc *
597 mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
598 {
599
600         return (mii_phy_match_gen(ma, mpd, sizeof(struct mii_phydesc)));
601 }
602
603 int
604 mii_phy_dev_probe(device_t dev, const struct mii_phydesc *mpd, int mrv)
605 {
606
607         mpd = mii_phy_match(device_get_ivars(dev), mpd);
608         if (mpd != NULL) {
609                 device_set_desc(dev, mpd->mpd_name);
610                 return (mrv);
611         }
612         return (ENXIO);
613 }
614
615 /*
616  * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
617  */
618 u_int
619 mii_phy_flowstatus(struct mii_softc *sc)
620 {
621         int anar, anlpar;
622
623         if ((sc->mii_flags & MIIF_DOPAUSE) == 0)
624                 return (0);
625
626         anar = PHY_READ(sc, MII_ANAR);
627         anlpar = PHY_READ(sc, MII_ANLPAR);
628
629         /*
630          * Check for 1000BASE-X.  Autonegotiation is a bit
631          * different on such devices.
632          */
633         if ((sc->mii_flags & MIIF_IS_1000X) != 0) {
634                 anar <<= 3;
635                 anlpar <<= 3;
636         }
637
638         if ((anar & ANAR_PAUSE_SYM) != 0 && (anlpar & ANLPAR_PAUSE_SYM) != 0)
639                 return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
640
641         if ((anar & ANAR_PAUSE_SYM) == 0) {
642                 if ((anar & ANAR_PAUSE_ASYM) != 0 &&
643                     (anlpar & ANLPAR_PAUSE_TOWARDS) != 0)
644                         return (IFM_FLOW | IFM_ETH_TXPAUSE);
645                 else
646                         return (0);
647         }
648
649         if ((anar & ANAR_PAUSE_ASYM) == 0) {
650                 if ((anlpar & ANLPAR_PAUSE_SYM) != 0)
651                         return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
652                 else
653                         return (0);
654         }
655
656         switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) {
657         case ANLPAR_PAUSE_NONE:
658                 return (0);
659         case ANLPAR_PAUSE_ASYM:
660                 return (IFM_FLOW | IFM_ETH_RXPAUSE);
661         default:
662                 return (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE);
663         }
664         /* NOTREACHED */
665 }