Annotation of sys/dev/mii/rlphy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: rlphy.c,v 1.27 2007/01/27 20:55:14 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1998, 1999 Jason L. Wright (jason@thought.net)
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * Driver for the internal PHY found on RTL8139 based nics, based
31: * on drivers for the 'exphy' (Internal 3Com phys) and 'nsphy'
32: * (National Semiconductor DP83840).
33: */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/device.h>
39: #include <sys/socket.h>
40: #include <sys/timeout.h>
41: #include <sys/errno.h>
42:
43: #include <net/if.h>
44: #include <net/if_media.h>
45: #include <netinet/in.h>
46: #include <netinet/if_ether.h>
47:
48: #include <dev/mii/mii.h>
49: #include <dev/mii/miivar.h>
50: #include <dev/mii/miidevs.h>
51: #include <machine/bus.h>
52: #include <dev/ic/rtl81x9reg.h>
53:
54: int rlphymatch(struct device *, void *, void *);
55: void rlphyattach(struct device *, struct device *, void *);
56:
57: struct cfattach rlphy_ca = {
58: sizeof(struct mii_softc), rlphymatch, rlphyattach, mii_phy_detach,
59: mii_phy_activate
60: };
61:
62: struct cfdriver rlphy_cd = {
63: NULL, "rlphy", DV_DULL
64: };
65:
66: int rlphy_service(struct mii_softc *, struct mii_data *, int);
67: void rlphy_status(struct mii_softc *);
68:
69: const struct mii_phy_funcs rlphy_funcs = {
70: rlphy_service, rlphy_status, mii_phy_reset,
71: };
72:
73: static const struct mii_phydesc rlphys[] = {
74: { MII_OUI_REALTEK, MII_MODEL_REALTEK_RTL8201L,
75: MII_STR_REALTEK_RTL8201L },
76: { MII_OUI_ICPLUS, MII_MODEL_ICPLUS_IP101,
77: MII_STR_ICPLUS_IP101 },
78:
79: { 0, 0,
80: NULL },
81: };
82: int
83: rlphymatch(struct device *parent, void *match, void *aux)
84: {
85: struct mii_attach_args *ma = aux;
86: char *devname;
87:
88: devname = parent->dv_cfdata->cf_driver->cd_name;
89:
90: if (mii_phy_match(ma, rlphys) != NULL)
91: return (10);
92:
93: if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
94: MII_MODEL(ma->mii_id2) != 0)
95: return (0);
96:
97: if ((strcmp(devname, "re") != 0) &&
98: (strcmp(devname, "rl") != 0))
99: return (0);
100:
101: /*
102: * A "real" phy should get preference, but on the 8139 there
103: * is no phyid register.
104: */
105: return (5);
106: }
107:
108: void
109: rlphyattach(struct device *parent, struct device *self, void *aux)
110: {
111: struct mii_softc *sc = (struct mii_softc *)self;
112: struct mii_attach_args *ma = aux;
113: struct mii_data *mii = ma->mii_data;
114: const struct mii_phydesc *mpd;
115:
116: mpd = mii_phy_match(ma, rlphys);
117: if (mpd != NULL) {
118: printf(": %s, rev. %d\n", mpd->mpd_name,
119: MII_REV(ma->mii_id2));
120: } else
121: printf(": RTL internal PHY\n");
122:
123: sc->mii_inst = mii->mii_instance;
124: sc->mii_phy = ma->mii_phyno;
125: sc->mii_funcs = &rlphy_funcs;
126: sc->mii_pdata = mii;
127: sc->mii_flags = ma->mii_flags;
128:
129: sc->mii_flags |= MIIF_NOISOLATE;
130:
131: PHY_RESET(sc);
132:
133: sc->mii_capabilities =
134: PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
135: if (sc->mii_capabilities & BMSR_MEDIAMASK)
136: mii_phy_add_media(sc);
137: }
138:
139: int
140: rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
141: {
142: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
143:
144: if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
145: return (ENXIO);
146:
147: /*
148: * Can't isolate the RTL8139 phy, so it has to be the only one.
149: */
150: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
151: panic("rlphy_service: attempt to isolate phy");
152:
153: switch (cmd) {
154: case MII_POLLSTAT:
155: break;
156:
157: case MII_MEDIACHG:
158: /*
159: * If the interface is not up, don't do anything.
160: */
161: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
162: break;
163:
164: switch (IFM_SUBTYPE(ife->ifm_media)) {
165: case IFM_AUTO:
166: /*
167: * If we're already in auto mode, just return.
168: */
169: if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
170: return (0);
171: (void) mii_phy_auto(sc, 0);
172: break;
173: case IFM_100_T4:
174: /*
175: * XXX Not supported as a manual setting right now.
176: */
177: return (EINVAL);
178: default:
179: /*
180: * BMCR data is stored in the ifmedia entry.
181: */
182: PHY_WRITE(sc, MII_ANAR,
183: mii_anar(ife->ifm_media));
184: PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
185: }
186: break;
187:
188: case MII_TICK:
189: /*
190: * Is the interface even up?
191: */
192: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
193: return (0);
194:
195: /*
196: * Only used for autonegotiation.
197: */
198: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
199: break;
200:
201: /*
202: * The RealTek PHY's autonegotiation doesn't need to be
203: * kicked; it continues in the background.
204: */
205: break;
206:
207: case MII_DOWN:
208: mii_phy_down(sc);
209: return (0);
210: }
211:
212: /* Update the media status. */
213: mii_phy_status(sc);
214:
215: /* Callback if something changed. */
216: mii_phy_update(sc, cmd);
217: return (0);
218: }
219:
220: void
221: rlphy_status(struct mii_softc *sc)
222: {
223: struct mii_data *mii = sc->mii_pdata;
224: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
225: int bmsr, bmcr, anlpar;
226: char *devname;
227:
228: devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
229:
230: mii->mii_media_status = IFM_AVALID;
231: mii->mii_media_active = IFM_ETHER;
232:
233: bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
234: if (bmsr & BMSR_LINK)
235: mii->mii_media_status |= IFM_ACTIVE;
236:
237: bmcr = PHY_READ(sc, MII_BMCR);
238: if (bmcr & BMCR_ISO) {
239: mii->mii_media_active |= IFM_NONE;
240: mii->mii_media_status = 0;
241: return;
242: }
243:
244: if (bmcr & BMCR_LOOP)
245: mii->mii_media_active |= IFM_LOOP;
246:
247: if (bmcr & BMCR_AUTOEN) {
248: /*
249: * NWay autonegotiation takes the highest-order common
250: * bit of the ANAR and ANLPAR (i.e. best media advertised
251: * both by us and our link partner).
252: */
253: if ((bmsr & BMSR_ACOMP) == 0) {
254: /* Erg, still trying, I guess... */
255: mii->mii_media_active |= IFM_NONE;
256: return;
257: }
258:
259: if ((anlpar = PHY_READ(sc, MII_ANAR) &
260: PHY_READ(sc, MII_ANLPAR))) {
261: if (anlpar & ANLPAR_T4)
262: mii->mii_media_active |= IFM_100_T4|IFM_HDX;
263: else if (anlpar & ANLPAR_TX_FD)
264: mii->mii_media_active |= IFM_100_TX|IFM_FDX;
265: else if (anlpar & ANLPAR_TX)
266: mii->mii_media_active |= IFM_100_TX|IFM_HDX;
267: else if (anlpar & ANLPAR_10_FD)
268: mii->mii_media_active |= IFM_10_T|IFM_FDX;
269: else if (anlpar & ANLPAR_10)
270: mii->mii_media_active |= IFM_10_T|IFM_HDX;
271: else
272: mii->mii_media_active |= IFM_NONE;
273: return;
274: }
275:
276: /*
277: * If the other side doesn't support NWAY, then the
278: * best we can do is determine if we have a 10Mbps or
279: * 100Mbps link. There's no way to know if the link
280: * is full or half duplex, so we default to half duplex
281: * and hope that the user is clever enough to manually
282: * change the media settings if we're wrong.
283: */
284:
285: /*
286: * The RealTek PHY supports non-NWAY link speed
287: * detection, however it does not report the link
288: * detection results via the ANLPAR or BMSR registers.
289: * (What? RealTek doesn't do things the way everyone
290: * else does? I'm just shocked, shocked I tell you.)
291: * To determine the link speed, we have to do one
292: * of two things:
293: *
294: * - If this is a standalone RealTek RTL8201(L) PHY,
295: * we can determine the link speed by testing bit 0
296: * in the magic, vendor-specific register at offset
297: * 0x19.
298: *
299: * - If this is a RealTek MAC with integrated PHY, we
300: * can test the 'SPEED10' bit of the MAC's media status
301: * register.
302: */
303: if (strcmp("rl", devname) == 0 ||
304: strcmp("re", devname) == 0) {
305: if (PHY_READ(sc, RL_MEDIASTAT) & RL_MEDIASTAT_SPEED10)
306: mii->mii_media_active |= IFM_10_T;
307: else
308: mii->mii_media_active |= IFM_100_TX;
309: } else {
310: if (PHY_READ(sc, 0x0019) & 0x01)
311: mii->mii_media_active |= IFM_100_TX;
312: else
313: mii->mii_media_active |= IFM_10_T;
314: }
315: mii->mii_media_active |= IFM_HDX;
316: } else
317: mii->mii_media_active = ife->ifm_media;
318: }
CVSweb