Annotation of sys/dev/mii/dcphy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: dcphy.c,v 1.18 2006/12/27 19:11:08 kettenis Exp $ */
2:
3: /*
4: * Copyright (c) 1997, 1998, 1999
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/dcphy.c,v 1.6 2000/10/05 17:36:14 wpaul Exp $
35: */
36:
37: /*
38: * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
39: * controllers. Technically we're abusing the miibus code to handle
40: * media selection and NWAY support here since there is no MII
41: * interface. However the logical operations are roughly the same,
42: * and the alternative is to create a fake MII interface in the driver,
43: * which is harder to do.
44: */
45:
46: #include <sys/param.h>
47: #include <sys/device.h>
48: #include <sys/systm.h>
49: #include <sys/kernel.h>
50: #include <sys/socket.h>
51: #include <sys/timeout.h>
52: #include <sys/errno.h>
53:
54: #include <net/if.h>
55: #include <net/if_dl.h>
56: #include <net/if_types.h>
57: #include <net/if_media.h>
58: #include <netinet/in.h>
59: #include <netinet/if_ether.h>
60:
61: #include <dev/mii/mii.h>
62: #include <dev/mii/miivar.h>
63: #include <dev/mii/miidevs.h>
64:
65: #include <machine/bus.h>
66:
67: #include <dev/pci/pcivar.h>
68:
69: #include <dev/ic/dcreg.h>
70:
71: #define DC_SETBIT(sc, reg, x) \
72: CSR_WRITE_4(sc, reg, \
73: CSR_READ_4(sc, reg) | x)
74:
75: #define DC_CLRBIT(sc, reg, x) \
76: CSR_WRITE_4(sc, reg, \
77: CSR_READ_4(sc, reg) & ~x)
78:
79: #define MIIF_AUTOTIMEOUT 0x0004
80:
81: /*
82: * This is the subsystem ID for the built-in 21143 ethernet
83: * in several Compaq Presario systems. Apparently these are
84: * 10Mbps only, so we need to treat them specially.
85: */
86: #define COMPAQ_PRESARIO_ID 0xb0bb0e11
87:
88: int dcphy_match(struct device *, void *, void *);
89: void dcphy_attach(struct device *, struct device *, void *);
90:
91: struct cfattach dcphy_ca = {
92: sizeof(struct mii_softc), dcphy_match, dcphy_attach, mii_phy_detach,
93: mii_phy_activate
94: };
95:
96: struct cfdriver dcphy_cd = {
97: NULL, "dcphy", DV_DULL
98: };
99:
100: int dcphy_service(struct mii_softc *, struct mii_data *, int);
101: void dcphy_status(struct mii_softc *);
102: int dcphy_mii_phy_auto(struct mii_softc *, int);
103: void dcphy_reset(struct mii_softc *);
104:
105: const struct mii_phy_funcs dcphy_funcs = {
106: dcphy_service, dcphy_status, dcphy_reset,
107: };
108:
109: int
110: dcphy_match(struct device *parent, void *match, void *aux)
111: {
112: struct mii_attach_args *ma = aux;
113:
114: /*
115: * The dc driver will report the 21143 vendor and device
116: * ID to let us know that it wants us to attach.
117: */
118: if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxDEC &&
119: MII_MODEL(ma->mii_id2) == MII_MODEL_xxDEC_xxDC)
120: return (10);
121:
122: return (0);
123: }
124:
125: void
126: dcphy_attach(struct device *parent, struct device *self, void *aux)
127: {
128: struct mii_softc *sc = (struct mii_softc *)self;
129: struct mii_attach_args *ma = aux;
130: struct mii_data *mii = ma->mii_data;
131: struct dc_softc *dc_sc;
132:
133: printf(": internal PHY\n");
134: sc->mii_inst = mii->mii_instance;
135: sc->mii_phy = ma->mii_phyno;
136: sc->mii_funcs = &dcphy_funcs;
137: sc->mii_pdata = mii;
138: sc->mii_flags = ma->mii_flags;
139: sc->mii_anegticks = 50;
140:
141: sc->mii_flags |= MIIF_NOISOLATE;
142:
143: dc_sc = mii->mii_ifp->if_softc;
144: CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
145: CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
146:
147: #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
148:
149: switch(dc_sc->dc_csid) {
150: case COMPAQ_PRESARIO_ID:
151: /* Example of how to only allow 10Mbps modes. */
152: sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
153: break;
154: default:
155: if (dc_sc->dc_pmode == DC_PMODE_SIA) {
156: sc->mii_capabilities =
157: BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
158: } else {
159: ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
160: sc->mii_inst), BMCR_LOOP|BMCR_S100);
161:
162: sc->mii_capabilities =
163: BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
164: BMSR_10TFDX|BMSR_10THDX;
165: }
166: break;
167: }
168:
169: if (dc_sc->dc_type == DC_TYPE_21145)
170: sc->mii_capabilities = BMSR_10THDX;
171:
172: sc->mii_capabilities &= ma->mii_capmask;
173: if (sc->mii_capabilities & BMSR_MEDIAMASK)
174: mii_phy_add_media(sc);
175: #undef ADD
176: }
177:
178: int
179: dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
180: {
181: struct dc_softc *dc_sc;
182: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
183: int reg;
184: u_int32_t mode;
185:
186: if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
187: return (ENXIO);
188:
189: dc_sc = mii->mii_ifp->if_softc;
190:
191: switch (cmd) {
192: case MII_POLLSTAT:
193: /*
194: * If we're not polling our PHY instance, just return.
195: */
196: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
197: return (0);
198: break;
199:
200: case MII_MEDIACHG:
201: /*
202: * If the media indicates a different PHY instance,
203: * isolate ourselves.
204: */
205: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
206: return (0);
207:
208: /*
209: * If the interface is not up, don't do anything.
210: */
211: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
212: break;
213:
214: sc->mii_flags = 0;
215: mii->mii_media_active = IFM_NONE;
216: mode = CSR_READ_4(dc_sc, DC_NETCFG);
217: mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
218: DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
219:
220: switch (IFM_SUBTYPE(ife->ifm_media)) {
221: case IFM_AUTO:
222: /*PHY_RESET(sc);*/
223: sc->mii_flags &= ~MIIF_DOINGAUTO;
224: (void) dcphy_mii_phy_auto(sc, 0);
225: break;
226: case IFM_100_TX:
227: PHY_RESET(sc);
228: DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
229: mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
230: DC_NETCFG_SCRAMBLER;
231: if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
232: mode |= DC_NETCFG_FULLDUPLEX;
233: else
234: mode &= ~DC_NETCFG_FULLDUPLEX;
235: CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
236: break;
237: case IFM_10_T:
238: DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
239: DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
240: if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
241: DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
242: else
243: DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
244: DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
245: DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
246: mode &= ~DC_NETCFG_PORTSEL;
247: mode |= DC_NETCFG_SPEEDSEL;
248: if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
249: mode |= DC_NETCFG_FULLDUPLEX;
250: else
251: mode &= ~DC_NETCFG_FULLDUPLEX;
252: CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
253: break;
254: default:
255: return (EINVAL);
256: }
257: break;
258:
259: case MII_TICK:
260: /*
261: * If we're not currently selected, just return.
262: */
263: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
264: return (0);
265:
266: /*
267: * Is the interface even up?
268: */
269: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
270: return (0);
271:
272: /*
273: * Only used for autonegotiation.
274: */
275: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
276: break;
277:
278: reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
279: if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
280: break;
281:
282: /*
283: * Only retry autonegotiation every mii_anegticks seconds.
284: *
285: * Otherwise, fall through to calling dcphy_status()
286: * since real Intel 21143 chips don't show valid link
287: * status until autonegotiation is switched off, and
288: * that only happens in dcphy_status(). Without this,
289: * successful autonegotation is never recognised on
290: * these chips.
291: */
292: if (++sc->mii_ticks <= sc->mii_anegticks)
293: break;
294:
295: sc->mii_ticks = 0;
296: sc->mii_flags &= ~MIIF_DOINGAUTO;
297: dcphy_mii_phy_auto(sc, 0);
298:
299: break;
300: }
301:
302: /* Update the media status. */
303: mii_phy_status(sc);
304:
305: /* Callback if something changed. */
306: mii_phy_update(sc, cmd);
307: return (0);
308: }
309:
310: void
311: dcphy_status(struct mii_softc *sc)
312: {
313: struct mii_data *mii = sc->mii_pdata;
314: int reg, anlpar, tstat = 0;
315: struct dc_softc *dc_sc;
316:
317: dc_sc = mii->mii_ifp->if_softc;
318:
319: mii->mii_media_status = IFM_AVALID;
320: mii->mii_media_active = IFM_ETHER;
321:
322: reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
323: if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
324: mii->mii_media_status |= IFM_ACTIVE;
325:
326: if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
327: /* Erg, still trying, I guess... */
328: tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
329: if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
330: if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
331: (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
332: goto skip;
333: mii->mii_media_active |= IFM_NONE;
334: return;
335: }
336:
337: if (tstat & DC_TSTAT_LP_CAN_NWAY) {
338: anlpar = tstat >> 16;
339: if (anlpar & ANLPAR_T4 &&
340: sc->mii_capabilities & BMSR_100TXHDX)
341: mii->mii_media_active |= IFM_100_T4|IFM_HDX;
342: else if (anlpar & ANLPAR_TX_FD &&
343: sc->mii_capabilities & BMSR_100TXFDX)
344: mii->mii_media_active |= IFM_100_TX|IFM_FDX;
345: else if (anlpar & ANLPAR_TX &&
346: sc->mii_capabilities & BMSR_100TXHDX)
347: mii->mii_media_active |= IFM_100_TX|IFM_HDX;
348: else if (anlpar & ANLPAR_10_FD)
349: mii->mii_media_active |= IFM_10_T|IFM_FDX;
350: else if (anlpar & ANLPAR_10)
351: mii->mii_media_active |= IFM_10_T|IFM_HDX;
352: else
353: mii->mii_media_active |= IFM_NONE;
354: if (DC_IS_INTEL(dc_sc))
355: DC_CLRBIT(dc_sc, DC_10BTCTRL,
356: DC_TCTL_AUTONEGENBL);
357: return;
358: }
359:
360: /*
361: * If the other side doesn't support NWAY, then the
362: * best we can do is determine if we have a 10Mbps or
363: * 100Mbps link. There's no way to know if the link
364: * is full or half duplex, so we default to half duplex
365: * and hope that the user is clever enough to manually
366: * change the media settings if we're wrong.
367: */
368: if (!(reg & DC_TSTAT_LS100))
369: mii->mii_media_active |= IFM_100_TX|IFM_HDX;
370: else if (!(reg & DC_TSTAT_LS10))
371: mii->mii_media_active |= IFM_10_T|IFM_HDX;
372: else
373: mii->mii_media_active |= IFM_NONE;
374: if (DC_IS_INTEL(dc_sc))
375: DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
376: return;
377: }
378:
379: skip:
380: if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
381: mii->mii_media_active |= IFM_10_T;
382: else
383: mii->mii_media_active |= IFM_100_TX;
384:
385: if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
386: mii->mii_media_active |= IFM_FDX;
387: else
388: mii->mii_media_active |= IFM_HDX;
389: }
390:
391: int
392: dcphy_mii_phy_auto(struct mii_softc *mii, int waitfor)
393: {
394: int i;
395: struct dc_softc *sc;
396:
397: sc = mii->mii_pdata->mii_ifp->if_softc;
398:
399: if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
400: DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
401: DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
402: DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
403: if (mii->mii_capabilities & BMSR_100TXHDX)
404: CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
405: else
406: CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
407: DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
408: DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
409: DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
410: }
411:
412: if (waitfor) {
413: /* Wait 500ms for it to complete. */
414: for (i = 0; i < 500; i++) {
415: if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
416: == DC_ASTAT_AUTONEGCMP)
417: return (0);
418: DELAY(1000);
419: }
420: /*
421: * Don't need to worry about clearing MIIF_DOINGAUTO.
422: * If that's set, a timeout is pending, and it will
423: * clear the flag.
424: */
425: return (EIO);
426: }
427:
428: /*
429: * Just let it finish asynchronously. This is for the benefit of
430: * the tick handler driving autonegotiation. Don't want 500ms
431: * delays all the time while the system is running!
432: */
433: if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
434: mii->mii_flags |= MIIF_DOINGAUTO;
435:
436: return (EJUSTRETURN);
437: }
438:
439: void
440: dcphy_reset(struct mii_softc *mii)
441: {
442: struct dc_softc *sc;
443:
444: sc = mii->mii_pdata->mii_ifp->if_softc;
445:
446: DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
447: DELAY(1000);
448: DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
449:
450: return;
451: }
CVSweb