rlphy.c revision 50758
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: head/sys/dev/mii/rlphy.c 50758 1999-09-01 17:07:27Z wpaul $
33 */
34
35/*
36 * driver for RealTek 8139 internal PHYs
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/socket.h>
44#include <sys/bus.h>
45
46#include <net/if.h>
47#include <net/if_media.h>
48
49#include <dev/mii/mii.h>
50#include <dev/mii/miivar.h>
51
52#include "miibus_if.h"
53
54#if !defined(lint)
55static const char rcsid[] =
56   "$FreeBSD: head/sys/dev/mii/rlphy.c 50758 1999-09-01 17:07:27Z wpaul $";
57#endif
58
59static int rlphy_probe		__P((device_t));
60static int rlphy_attach		__P((device_t));
61static int rlphy_detach		__P((device_t));
62
63static 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
72static devclass_t rlphy_devclass;
73
74static driver_t rlphy_driver = {
75	"rlphy",
76	rlphy_methods,
77	sizeof(struct mii_softc)
78};
79
80DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0);
81
82int	rlphy_service __P((struct mii_softc *, struct mii_data *, int));
83void	rlphy_reset __P((struct mii_softc *));
84
85static 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	/*
95	 * RealTek PHY doesn't have vendor/device ID registers:
96	 * the rl driver fakes up a return value of all zeros.
97	 */
98	if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
99	    MII_MODEL(ma->mii_id2) != 0)
100		return (ENXIO);
101
102	/*
103	 * Make sure the parent is an `rl'.
104	 */
105	if (strcmp(device_get_name(parent), "rl") != 0)
106		return (ENXIO);
107
108	device_set_desc(dev, "RealTek internal media interface");
109
110	return (0);
111}
112
113static int rlphy_attach(dev)
114	device_t		dev;
115{
116	struct mii_softc	*sc;
117	struct mii_attach_args	*ma;
118	struct mii_data		*mii;
119
120	sc = device_get_softc(dev);
121	ma = device_get_ivars(dev);
122	sc->mii_dev = device_get_parent(dev);
123	mii = device_get_softc(sc->mii_dev);
124
125	/*
126	 * The RealTek PHY can never be isolated, so never allow non-zero
127	 * instances!
128	 */
129	if (mii->mii_instance != 0) {
130		device_printf(dev, "ignoring this PHY, non-zero instance\n");
131		return(ENXIO);
132	}
133
134	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
135
136	sc->mii_inst = mii->mii_instance;
137	sc->mii_phy = ma->mii_phyno;
138	sc->mii_service = rlphy_service;
139	sc->mii_pdata = mii;
140	mii->mii_instance++;
141
142	sc->mii_flags |= MIIF_NOISOLATE;
143
144#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
145
146#if 0 /* See above. */
147	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
148	    BMCR_ISO);
149#endif
150
151	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
152	    BMCR_LOOP|BMCR_S100);
153
154	rlphy_reset(sc);
155
156	sc->mii_capabilities =
157	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
158	device_printf(dev, " ");
159	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
160		printf("no media present");
161	else
162		mii_add_media(mii, sc->mii_capabilities,
163		    sc->mii_inst);
164	printf("\n");
165#undef ADD
166	MIIBUS_MEDIAINIT(sc->mii_dev);
167	return(0);
168}
169
170static int rlphy_detach(dev)
171	device_t		dev;
172{
173	struct mii_softc	*sc;
174	struct mii_data		*mii;
175
176	sc = device_get_softc(dev);
177	mii = device_get_softc(device_get_softc(dev));
178	sc->mii_dev = NULL;
179	LIST_REMOVE(sc, mii_list);
180
181	return(0);
182}
183
184int
185rlphy_service(sc, mii, cmd)
186	struct mii_softc *sc;
187	struct mii_data *mii;
188	int cmd;
189{
190	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
191
192	/*
193	 * We can't isolate the RealTek PHY, so it has to be the only one!
194	 */
195	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
196		panic("rlphy_service: can't isolate RealTek PHY");
197
198	switch (cmd) {
199	case MII_POLLSTAT:
200		break;
201
202	case MII_MEDIACHG:
203		/*
204		 * If the interface is not up, don't do anything.
205		 */
206		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
207			break;
208
209		switch (IFM_SUBTYPE(ife->ifm_media)) {
210		case IFM_AUTO:
211			/*
212			 * If we're already in auto mode, just return.
213			 */
214			if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
215				return (0);
216			(void) mii_phy_auto(sc, 0);
217			break;
218		case IFM_100_T4:
219			/*
220			 * XXX Not supported as a manual setting right now.
221			 */
222			return (EINVAL);
223		default:
224			/*
225			 * BMCR data is stored in the ifmedia entry.
226			 */
227			PHY_WRITE(sc, MII_ANAR,
228			    mii_anar(ife->ifm_media));
229			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
230		}
231		break;
232
233	case MII_TICK:
234		/*
235		 * Only used for autonegotiation.
236		 */
237		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
238			return (0);
239
240		/*
241		 * Is the interface even up?
242		 */
243		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
244			return (0);
245
246		/*
247		 * Only retry autonegotiation every 5 seconds.
248		 */
249		if (++sc->mii_ticks != 5)
250			return (0);
251
252		sc->mii_ticks = 0;
253
254		/*
255		 * The RealTek PHY's autonegotiation doesn't need to be
256		 * kicked; it continues in the background.
257		 */
258		break;
259	}
260
261	/* Update the media status. */
262	ukphy_status(sc);
263
264	/* Callback if something changed. */
265	if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
266		MIIBUS_STATCHG(sc->mii_dev);
267		sc->mii_active = mii->mii_media_active;
268	}
269	return (0);
270}
271
272void
273rlphy_reset(sc)
274	struct mii_softc *sc;
275{
276
277	mii_phy_reset(sc);
278
279	/*
280	 * XXX RealTek PHY doesn't set the BMCR properly after
281	 * XXX reset, which breaks autonegotiation.
282	 */
283	PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX);
284}
285