rlphy.c revision 92739
112048Speter/*
212048Speter * Copyright (c) 1997, 1998, 1999
350476Speter *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
412048Speter *
512048Speter * Redistribution and use in source and binary forms, with or without
612051Speter * modification, are permitted provided that the following conditions
712048Speter * are met:
812048Speter * 1. Redistributions of source code must retain the above copyright
933139Sjhay *    notice, this list of conditions and the following disclaimer.
1033139Sjhay * 2. Redistributions in binary form must reproduce the above copyright
1112048Speter *    notice, this list of conditions and the following disclaimer in the
1218003Speter *    documentation and/or other materials provided with the distribution.
1312480Speter * 3. All advertising materials mentioning features or use of this software
1412048Speter *    must display the following acknowledgement:
1512048Speter *	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 92739 2002-03-20 02:08:01Z alfred $
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/socket.h>
43#include <sys/bus.h>
44
45#include <net/if.h>
46#include <net/if_media.h>
47
48#include <dev/mii/mii.h>
49#include <dev/mii/miivar.h>
50
51#include "miibus_if.h"
52
53#if !defined(lint)
54static const char rcsid[] =
55   "$FreeBSD: head/sys/dev/mii/rlphy.c 92739 2002-03-20 02:08:01Z alfred $";
56#endif
57
58static int rlphy_probe		(device_t);
59static int rlphy_attach		(device_t);
60static int rlphy_detach		(device_t);
61
62static device_method_t rlphy_methods[] = {
63	/* device interface */
64	DEVMETHOD(device_probe,		rlphy_probe),
65	DEVMETHOD(device_attach,	rlphy_attach),
66	DEVMETHOD(device_detach,	rlphy_detach),
67	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
68	{ 0, 0 }
69};
70
71static devclass_t rlphy_devclass;
72
73static driver_t rlphy_driver = {
74	"rlphy",
75	rlphy_methods,
76	sizeof(struct mii_softc)
77};
78
79DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0);
80
81static int	rlphy_service(struct mii_softc *, struct mii_data *, int);
82
83static int rlphy_probe(dev)
84	device_t		dev;
85{
86	struct mii_attach_args *ma;
87	device_t		parent;
88
89	ma = device_get_ivars(dev);
90	parent = device_get_parent(device_get_parent(dev));
91
92	/*
93	 * RealTek PHY doesn't have vendor/device ID registers:
94	 * the rl driver fakes up a return value of all zeros.
95	 */
96	if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
97	    MII_MODEL(ma->mii_id2) != 0)
98		return (ENXIO);
99
100	/*
101	 * Make sure the parent is an `rl'.
102	 */
103	if (strcmp(device_get_name(parent), "rl") != 0)
104		return (ENXIO);
105
106	device_set_desc(dev, "RealTek internal media interface");
107
108	return (0);
109}
110
111static int rlphy_attach(dev)
112	device_t		dev;
113{
114	struct mii_softc	*sc;
115	struct mii_attach_args	*ma;
116	struct mii_data		*mii;
117
118	sc = device_get_softc(dev);
119	ma = device_get_ivars(dev);
120	sc->mii_dev = device_get_parent(dev);
121	mii = device_get_softc(sc->mii_dev);
122
123	/*
124	 * The RealTek PHY can never be isolated, so never allow non-zero
125	 * instances!
126	 */
127	if (mii->mii_instance != 0) {
128		device_printf(dev, "ignoring this PHY, non-zero instance\n");
129		return(ENXIO);
130	}
131
132	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
133
134	sc->mii_inst = mii->mii_instance;
135	sc->mii_phy = ma->mii_phyno;
136	sc->mii_service = rlphy_service;
137	sc->mii_pdata = mii;
138	mii->mii_instance++;
139
140	sc->mii_flags |= MIIF_NOISOLATE;
141
142#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
143
144#if 0 /* See above. */
145	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
146	    BMCR_ISO);
147#endif
148
149	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
150	    BMCR_LOOP|BMCR_S100);
151
152	mii_phy_reset(sc);
153
154	sc->mii_capabilities =
155	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
156	device_printf(dev, " ");
157	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
158		printf("no media present");
159	else
160		mii_add_media(mii, sc->mii_capabilities,
161		    sc->mii_inst);
162	printf("\n");
163#undef ADD
164	MIIBUS_MEDIAINIT(sc->mii_dev);
165	return(0);
166}
167
168static int rlphy_detach(dev)
169	device_t		dev;
170{
171	struct mii_softc	*sc;
172	struct mii_data		*mii;
173
174	sc = device_get_softc(dev);
175	mii = device_get_softc(device_get_softc(dev));
176	mii_phy_auto_stop(sc);
177	sc->mii_dev = NULL;
178	LIST_REMOVE(sc, mii_list);
179
180	return(0);
181}
182
183static int
184rlphy_service(sc, mii, cmd)
185	struct mii_softc *sc;
186	struct mii_data *mii;
187	int cmd;
188{
189	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
190
191	/*
192	 * We can't isolate the RealTek PHY, so it has to be the only one!
193	 */
194	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
195		panic("rlphy_service: can't isolate RealTek PHY");
196
197	switch (cmd) {
198	case MII_POLLSTAT:
199		break;
200
201	case MII_MEDIACHG:
202		/*
203		 * If the interface is not up, don't do anything.
204		 */
205		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
206			break;
207
208		switch (IFM_SUBTYPE(ife->ifm_media)) {
209		case IFM_AUTO:
210			/*
211			 * If we're already in auto mode, just return.
212			 */
213			if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
214				return (0);
215			(void) mii_phy_auto(sc, 0);
216			break;
217		case IFM_100_T4:
218			/*
219			 * XXX Not supported as a manual setting right now.
220			 */
221			return (EINVAL);
222		default:
223			/*
224			 * BMCR data is stored in the ifmedia entry.
225			 */
226			PHY_WRITE(sc, MII_ANAR,
227			    mii_anar(ife->ifm_media));
228			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
229		}
230		break;
231
232	case MII_TICK:
233		/*
234		 * Is the interface even up?
235		 */
236		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
237			return (0);
238
239		/*
240		 * Only used for autonegotiation.
241		 */
242		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
243			break;
244
245		/*
246		 * The RealTek PHY's autonegotiation doesn't need to be
247		 * kicked; it continues in the background.
248		 */
249		break;
250	}
251
252	/* Update the media status. */
253	ukphy_status(sc);
254
255	/* Callback if something changed. */
256	mii_phy_update(sc, cmd);
257	return (0);
258}
259