Annotation of sys/dev/mii/xmphy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: xmphy.c,v 1.17 2006/12/31 15:04:33 krw Exp $ */
2:
3: /*
4: * Copyright (c) 2000
5: * Bill Paul <wpaul@ee.columbia.edu>. 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: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Bill Paul.
18: * 4. Neither the name of the author nor the names of any co-contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32: * THE POSSIBILITY OF SUCH DAMAGE.
33: *
34: * $FreeBSD: src/sys/dev/mii/xmphy.c,v 1.1 2000/04/22 01:58:18 wpaul Exp $
35: */
36:
37: /*
38: * driver for the XaQti XMAC II's internal PHY. This is sort of
39: * like a 10/100 PHY, except the only thing we're really autoselecting
40: * here is full/half duplex. Speed is always 1000mbps.
41: */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/kernel.h>
46: #include <sys/device.h>
47: #include <sys/socket.h>
48: #include <sys/errno.h>
49:
50: #include <net/if.h>
51: #include <net/if_media.h>
52:
53: #include <dev/mii/mii.h>
54: #include <dev/mii/miivar.h>
55: #include <dev/mii/miidevs.h>
56:
57: #include <dev/mii/xmphyreg.h>
58:
59: int xmphy_probe(struct device *, void *, void *);
60: void xmphy_attach(struct device *, struct device *, void *);
61:
62: struct cfattach xmphy_ca = {
63: sizeof(struct mii_softc), xmphy_probe, xmphy_attach, mii_phy_detach,
64: mii_phy_activate
65: };
66:
67: struct cfdriver xmphy_cd = {
68: NULL, "xmphy", DV_DULL
69: };
70:
71: int xmphy_service(struct mii_softc *, struct mii_data *, int);
72: void xmphy_status(struct mii_softc *);
73:
74: int xmphy_mii_phy_auto(struct mii_softc *);
75:
76: const struct mii_phy_funcs xmphy_funcs = {
77: xmphy_service, xmphy_status, mii_phy_reset,
78: };
79:
80: static const struct mii_phydesc xmphys[] = {
81: { MII_OUI_xxXAQTI, MII_MODEL_XAQTI_XMACII,
82: MII_STR_XAQTI_XMACII },
83:
84: { MII_OUI_JATO, MII_MODEL_JATO_BASEX,
85: MII_STR_JATO_BASEX },
86:
87: { 0, 0,
88: NULL },
89: };
90:
91: int xmphy_probe(struct device *parent, void *match, void *aux)
92: {
93: struct mii_attach_args *ma = aux;
94:
95: if (mii_phy_match(ma, xmphys) != NULL)
96: return (10);
97:
98: return (0);
99: }
100:
101: void
102: xmphy_attach(struct device *parent, struct device *self, void *aux)
103: {
104: struct mii_softc *sc = (struct mii_softc *)self;
105: struct mii_attach_args *ma = aux;
106: struct mii_data *mii = ma->mii_data;
107: const struct mii_phydesc *mpd;
108:
109: mpd = mii_phy_match(ma, xmphys);
110: printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
111:
112: sc->mii_inst = mii->mii_instance;
113: sc->mii_phy = ma->mii_phyno;
114: sc->mii_funcs = &xmphy_funcs;
115: sc->mii_pdata = mii;
116: sc->mii_flags = ma->mii_flags;
117: sc->mii_anegticks = MII_ANEGTICKS;
118:
119: sc->mii_flags |= MIIF_NOISOLATE;
120:
121: #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
122:
123: ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
124: BMCR_ISO);
125:
126: PHY_RESET(sc);
127:
128: ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst),
129: XMPHY_BMCR_FDX);
130: ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0);
131: ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
132:
133: #undef ADD
134: }
135:
136: int
137: xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
138: {
139: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
140: int reg;
141:
142: if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
143: return (ENXIO);
144:
145: switch (cmd) {
146: case MII_POLLSTAT:
147: /*
148: * If we're not polling our PHY instance, just return.
149: */
150: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
151: return (0);
152: break;
153:
154: case MII_MEDIACHG:
155: /*
156: * If the media indicates a different PHY instance,
157: * isolate ourselves.
158: */
159: if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
160: reg = PHY_READ(sc, MII_BMCR);
161: PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
162: return (0);
163: }
164:
165: /*
166: * If the interface is not up, don't do anything.
167: */
168: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
169: break;
170:
171: switch (IFM_SUBTYPE(ife->ifm_media)) {
172: case IFM_AUTO:
173: (void) xmphy_mii_phy_auto(sc);
174: break;
175: case IFM_1000_SX:
176: PHY_RESET(sc);
177: if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
178: PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX);
179: PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX);
180: } else {
181: PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX);
182: PHY_WRITE(sc, XMPHY_MII_BMCR, 0);
183: }
184: break;
185: case IFM_100_T4:
186: case IFM_100_TX:
187: case IFM_10_T:
188: default:
189: return (EINVAL);
190: }
191: break;
192:
193: case MII_TICK:
194: /*
195: * If we're not currently selected, just return.
196: */
197: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
198: return (0);
199:
200: /*
201: * Is the interface even up?
202: */
203: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
204: return (0);
205:
206: /*
207: * Only used for autonegotiation.
208: */
209: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
210: break;
211:
212: /*
213: * Check to see if we have link. If we do, we don't
214: * need to restart the autonegotiation process. Read
215: * the BMSR twice in case it's latched.
216: */
217: reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
218: if (reg & BMSR_LINK)
219: break;
220:
221: /*
222: * Only retry autonegotiation every mii_anegticks seconds.
223: */
224: if (++sc->mii_ticks <= sc->mii_anegticks)
225: break;
226:
227: sc->mii_ticks = 0;
228: PHY_RESET(sc);
229:
230: xmphy_mii_phy_auto(sc);
231: break;
232: }
233:
234: /* Update the media status. */
235: mii_phy_status(sc);
236:
237: /* Callback if something changed. */
238: mii_phy_update(sc, cmd);
239: return (0);
240: }
241:
242: void
243: xmphy_status(struct mii_softc *sc)
244: {
245: struct mii_data *mii = sc->mii_pdata;
246: int bmsr, bmcr, anlpar;
247:
248: mii->mii_media_status = IFM_AVALID;
249: mii->mii_media_active = IFM_ETHER;
250:
251: bmsr = PHY_READ(sc, XMPHY_MII_BMSR) |
252: PHY_READ(sc, XMPHY_MII_BMSR);
253: if (bmsr & XMPHY_BMSR_LINK)
254: mii->mii_media_status |= IFM_ACTIVE;
255:
256: /* Do dummy read of extended status register. */
257: bmcr = PHY_READ(sc, XMPHY_MII_EXTSTS);
258:
259: bmcr = PHY_READ(sc, XMPHY_MII_BMCR);
260:
261: if (bmcr & XMPHY_BMCR_LOOP)
262: mii->mii_media_active |= IFM_LOOP;
263:
264:
265: if (bmcr & XMPHY_BMCR_AUTOEN) {
266: if ((bmsr & XMPHY_BMSR_ACOMP) == 0) {
267: if (bmsr & XMPHY_BMSR_LINK) {
268: mii->mii_media_active |= IFM_1000_SX|IFM_HDX;
269: return;
270: }
271: /* Erg, still trying, I guess... */
272: mii->mii_media_active |= IFM_NONE;
273: return;
274: }
275:
276: mii->mii_media_active |= IFM_1000_SX;
277: anlpar = PHY_READ(sc, XMPHY_MII_ANAR) &
278: PHY_READ(sc, XMPHY_MII_ANLPAR);
279: if (anlpar & XMPHY_ANLPAR_FDX)
280: mii->mii_media_active |= IFM_FDX;
281: else
282: mii->mii_media_active |= IFM_HDX;
283: return;
284: }
285:
286: mii->mii_media_active |= IFM_1000_SX;
287: if (bmcr & XMPHY_BMCR_FDX)
288: mii->mii_media_active |= IFM_FDX;
289: else
290: mii->mii_media_active |= IFM_HDX;
291:
292: return;
293: }
294:
295:
296: int
297: xmphy_mii_phy_auto(struct mii_softc *sc)
298: {
299: int anar = 0;
300:
301: anar = PHY_READ(sc, XMPHY_MII_ANAR);
302: anar |= XMPHY_ANAR_FDX|XMPHY_ANAR_HDX;
303: PHY_WRITE(sc, XMPHY_MII_ANAR, anar);
304: DELAY(1000);
305: PHY_WRITE(sc, XMPHY_MII_BMCR,
306: XMPHY_BMCR_AUTOEN | XMPHY_BMCR_STARTNEG);
307:
308: return (EJUSTRETURN);
309: }
CVSweb