Remove some duplicate FreeBSD CVS IDs, move some IDs to better places.
[dragonfly.git] / sys / dev / netif / mii_layer / rlphy.c
1 /*
2  * Copyright (c) 1997, 1998, 1999
3  *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
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
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $FreeBSD: src/sys/dev/mii/rlphy.c,v 1.2.2.4 2002/11/08 21:53:49 semenu Exp $
33  * $DragonFly: src/sys/dev/netif/mii_layer/rlphy.c,v 1.6 2005/02/21 18:40:36 joerg Exp $
34  */
35
36 /*
37  * driver for RealTek 8139 internal 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/bus.h>
45
46 #include <net/if.h>
47 #include <net/if_arp.h>
48 #include <net/if_media.h>
49
50 #include "mii.h"
51 #include "miivar.h"
52 #include "miidevs.h"
53
54 #include <machine/bus.h>
55 #include "../rl/if_rlreg.h"
56
57 #include "miibus_if.h"
58
59 static int rlphy_probe          (device_t);
60 static int rlphy_attach         (device_t);
61 static int rlphy_detach         (device_t);
62
63 static device_method_t rlphy_methods[] = {
64         /* device interface */
65         DEVMETHOD(device_probe,         rlphy_probe),
66         DEVMETHOD(device_attach,        rlphy_attach),
67         DEVMETHOD(device_detach,        rlphy_detach),
68         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
69         { 0, 0 }
70 };
71
72 static devclass_t rlphy_devclass;
73
74 static driver_t rlphy_driver = {
75         "rlphy",
76         rlphy_methods,
77         sizeof(struct mii_softc)
78 };
79
80 DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0);
81
82 int     rlphy_service (struct mii_softc *, struct mii_data *, int);
83 void    rlphy_status (struct mii_softc *);
84
85 static int rlphy_probe(dev)
86         device_t                dev;
87 {
88         struct mii_attach_args *ma;
89         device_t                parent;
90
91         ma = device_get_ivars(dev);
92         parent = device_get_parent(device_get_parent(dev));
93
94         /* Test for RealTek 8201L PHY */
95         if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_REALTEK &&
96             MII_MODEL(ma->mii_id2) == MII_MODEL_REALTEK_RTL8201L) {
97                 device_set_desc(dev, MII_STR_REALTEK_RTL8201L);
98                 return(0);
99         }
100
101         /*
102          * RealTek PHY doesn't have vendor/device ID registers:
103          * the rl driver fakes up a return value of all zeros.
104          */
105         if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
106             MII_MODEL(ma->mii_id2) != 0)
107                 return (ENXIO);
108
109         /*
110          * Make sure the parent is an `rl'.
111          */
112         if (strcmp(device_get_name(parent), "rl") != 0)
113                 return (ENXIO);
114
115         device_set_desc(dev, "RealTek internal media interface");
116
117         return (0);
118 }
119
120 static int rlphy_attach(dev)
121         device_t                dev;
122 {
123         struct mii_softc        *sc;
124         struct mii_attach_args  *ma;
125         struct mii_data         *mii;
126
127         sc = device_get_softc(dev);
128         ma = device_get_ivars(dev);
129         mii_softc_init(sc);
130         sc->mii_dev = device_get_parent(dev);
131         mii = device_get_softc(sc->mii_dev);
132
133         /*
134          * The RealTek PHY can never be isolated, so never allow non-zero
135          * instances!
136          */
137         if (mii->mii_instance != 0) {
138                 device_printf(dev, "ignoring this PHY, non-zero instance\n");
139                 return(ENXIO);
140         }
141
142         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
143
144         sc->mii_inst = mii->mii_instance;
145         sc->mii_phy = ma->mii_phyno;
146         sc->mii_service = rlphy_service;
147         sc->mii_pdata = mii;
148         mii->mii_instance++;
149
150         sc->mii_flags |= MIIF_NOISOLATE;
151
152 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
153
154 #if 0 /* See above. */
155         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
156             BMCR_ISO);
157 #endif
158
159         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
160             BMCR_LOOP|BMCR_S100);
161
162         mii_phy_reset(sc);
163
164         sc->mii_capabilities =
165             PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
166         device_printf(dev, " ");
167         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
168                 printf("no media present");
169         else
170                 mii_add_media(mii, sc->mii_capabilities,
171                     sc->mii_inst);
172         printf("\n");
173 #undef ADD
174         MIIBUS_MEDIAINIT(sc->mii_dev);
175         return(0);
176 }
177
178 static int rlphy_detach(dev)
179         device_t                dev;
180 {
181         struct mii_softc        *sc;
182         struct mii_data         *mii;
183
184         sc = device_get_softc(dev);
185         mii = device_get_softc(device_get_softc(dev));
186         mii_phy_auto_stop(sc);
187         sc->mii_dev = NULL;
188         LIST_REMOVE(sc, mii_list);
189
190         return(0);
191 }
192
193 int
194 rlphy_service(sc, mii, cmd)
195         struct mii_softc *sc;
196         struct mii_data *mii;
197         int cmd;
198 {
199         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
200
201         /*
202          * We can't isolate the RealTek PHY, so it has to be the only one!
203          */
204         if (IFM_INST(ife->ifm_media) != sc->mii_inst)
205                 panic("rlphy_service: can't isolate RealTek PHY");
206
207         switch (cmd) {
208         case MII_POLLSTAT:
209                 break;
210
211         case MII_MEDIACHG:
212                 /*
213                  * If the interface is not up, don't do anything.
214                  */
215                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
216                         break;
217
218                 switch (IFM_SUBTYPE(ife->ifm_media)) {
219                 case IFM_AUTO:
220                         /*
221                          * If we're already in auto mode, just return.
222                          */
223                         if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
224                                 return (0);
225                         (void) mii_phy_auto(sc, 0);
226                         break;
227                 case IFM_100_T4:
228                         /*
229                          * XXX Not supported as a manual setting right now.
230                          */
231                         return (EINVAL);
232                 default:
233                         /*
234                          * BMCR data is stored in the ifmedia entry.
235                          */
236                         PHY_WRITE(sc, MII_ANAR,
237                             mii_anar(ife->ifm_media));
238                         PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
239                 }
240                 break;
241
242         case MII_TICK:
243                 /*
244                  * Only used for autonegotiation.
245                  */
246                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
247                         return (0);
248
249                 /*
250                  * Is the interface even up?
251                  */
252                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
253                         return (0);
254
255                 /*
256                  * Only retry autonegotiation every 5 seconds.
257                  */
258                 if (++sc->mii_ticks != 5)
259                         return (0);
260
261                 sc->mii_ticks = 0;
262
263                 /*
264                  * The RealTek PHY's autonegotiation doesn't need to be
265                  * kicked; it continues in the background.
266                  */
267                 break;
268         }
269
270         /* Update the media status. */
271         rlphy_status(sc);
272
273         /* Callback if something changed. */
274         if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
275                 MIIBUS_STATCHG(sc->mii_dev);
276                 sc->mii_active = mii->mii_media_active;
277         }
278         return (0);
279 }
280
281 void
282 rlphy_status(phy)
283         struct mii_softc *phy;
284 {
285         struct mii_data *mii = phy->mii_pdata;
286         int bmsr, bmcr, anlpar;
287         device_t                parent;
288
289         mii->mii_media_status = IFM_AVALID;
290         mii->mii_media_active = IFM_ETHER;
291
292         bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
293         if (bmsr & BMSR_LINK)
294                 mii->mii_media_status |= IFM_ACTIVE;
295
296         bmcr = PHY_READ(phy, MII_BMCR);
297         if (bmcr & BMCR_ISO) {
298                 mii->mii_media_active |= IFM_NONE;
299                 mii->mii_media_status = 0;
300                 return;
301         }
302
303         if (bmcr & BMCR_LOOP)
304                 mii->mii_media_active |= IFM_LOOP;
305
306         if (bmcr & BMCR_AUTOEN) {
307                 /*
308                  * NWay autonegotiation takes the highest-order common
309                  * bit of the ANAR and ANLPAR (i.e. best media advertised
310                  * both by us and our link partner).
311                  */
312                 if ((bmsr & BMSR_ACOMP) == 0) {
313                         /* Erg, still trying, I guess... */
314                         mii->mii_media_active |= IFM_NONE;
315                         return;
316                 }
317
318                 if ((anlpar = PHY_READ(phy, MII_ANAR) &
319                     PHY_READ(phy, MII_ANLPAR))) {
320                         if (anlpar & ANLPAR_T4)
321                                 mii->mii_media_active |= IFM_100_T4;
322                         else if (anlpar & ANLPAR_TX_FD)
323                                 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
324                         else if (anlpar & ANLPAR_TX)
325                                 mii->mii_media_active |= IFM_100_TX;
326                         else if (anlpar & ANLPAR_10_FD)
327                                 mii->mii_media_active |= IFM_10_T|IFM_FDX;
328                         else if (anlpar & ANLPAR_10)
329                                 mii->mii_media_active |= IFM_10_T;
330                         else
331                                 mii->mii_media_active |= IFM_NONE; 
332                         return;
333                 }
334                 /*
335                  * If the other side doesn't support NWAY, then the
336                  * best we can do is determine if we have a 10Mbps or
337                  * 100Mbps link. There's no way to know if the link 
338                  * is full or half duplex, so we default to half duplex
339                  * and hope that the user is clever enough to manually
340                  * change the media settings if we're wrong.
341                  */
342
343
344                 /*
345                  * The RealTek PHY supports non-NWAY link speed
346                  * detection, however it does not report the link
347                  * detection results via the ANLPAR or BMSR registers.
348                  * (What? RealTek doesn't do things the way everyone
349                  * else does? I'm just shocked, shocked I tell you.)
350                  * To determine the link speed, we have to do one
351                  * of two things:
352                  *
353                  * - If this is a standalone RealTek RTL8201(L) PHY,
354                  *   we can determine the link speed by testing bit 0
355                  *   in the magic, vendor-specific register at offset
356                  *   0x19.
357                  *
358                  * - If this is a RealTek MAC with integrated PHY, we
359                  *   can test the 'SPEED10' bit of the MAC's media status
360                  *   register.
361                  */
362                 parent = device_get_parent(phy->mii_dev);
363                 if (strcmp(device_get_name(parent), "rl") != 0) {
364                         if (PHY_READ(phy, 0x0019) & 0x01)
365                                 mii->mii_media_active |= IFM_100_TX;
366                         else
367                                 mii->mii_media_active |= IFM_10_T;
368                 } else {
369                         if (PHY_READ(phy, RL_MEDIASTAT) &
370                             RL_MEDIASTAT_SPEED10)
371                                 mii->mii_media_active |= IFM_10_T;
372                         else
373                                 mii->mii_media_active |= IFM_100_TX;
374                 }
375
376         } else
377                 mii->mii_media_active = mii_media_from_bmcr(bmcr);
378 }