pnaphy.c revision 104094
1/*
2 * Copyright (c) 2000 Berkeley Software Design, Inc.
3 * Copyright (c) 1997, 1998, 1999, 2000
4 *	Bill Paul <wpaul@osd.bsdi.com>.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Bill Paul.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $FreeBSD: head/sys/dev/mii/pnaphy.c 104094 2002-09-28 17:15:38Z phk $
34 */
35
36/*
37 * driver for homePNA PHYs
38 * This is really just a stub that allows us to identify homePNA-based
39 * transceicers and display the link status. MII-based homePNA PHYs
40 * only support one media type and no autonegotiation. If we were
41 * really clever, we could tweak some of the vendor-specific registers
42 * to optimize the link.
43 */
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/socket.h>
50#include <sys/errno.h>
51#include <sys/module.h>
52#include <sys/bus.h>
53
54#include <net/if.h>
55#include <net/if_media.h>
56
57
58#include <dev/mii/mii.h>
59#include <dev/mii/miivar.h>
60#include <dev/mii/miidevs.h>
61
62#include "miibus_if.h"
63
64#if !defined(lint)
65static const char rcsid[] =
66  "$FreeBSD: head/sys/dev/mii/pnaphy.c 104094 2002-09-28 17:15:38Z phk $";
67#endif
68
69static int pnaphy_probe		(device_t);
70static int pnaphy_attach	(device_t);
71
72static device_method_t pnaphy_methods[] = {
73	/* device interface */
74	DEVMETHOD(device_probe,		pnaphy_probe),
75	DEVMETHOD(device_attach,	pnaphy_attach),
76	DEVMETHOD(device_detach,	mii_phy_detach),
77	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
78	{ 0, 0 }
79};
80
81static devclass_t pnaphy_devclass;
82
83static driver_t pnaphy_driver = {
84	"pnaphy",
85	pnaphy_methods,
86	sizeof(struct mii_softc)
87};
88
89DRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
90
91static int	pnaphy_service(struct mii_softc *, struct mii_data *,int);
92
93static int
94pnaphy_probe(dev)
95	device_t		dev;
96{
97
98	struct mii_attach_args	*ma;
99
100	ma = device_get_ivars(dev);
101
102	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
103	    MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
104		device_set_desc(dev, MII_STR_AMD_79c978);
105		return(0);
106	}
107
108	return(ENXIO);
109}
110
111static int
112pnaphy_attach(dev)
113	device_t		dev;
114{
115	struct mii_softc *sc;
116	struct mii_attach_args *ma;
117	struct mii_data *mii;
118	const char *sep = "";
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	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
125
126	sc->mii_inst = mii->mii_instance;
127	sc->mii_phy = ma->mii_phyno;
128	sc->mii_service = pnaphy_service;
129	sc->mii_pdata = mii;
130
131	mii->mii_instance++;
132
133	sc->mii_flags |= MIIF_NOISOLATE;
134
135#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
136#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
137
138	mii_phy_reset(sc);
139
140	sc->mii_capabilities =
141	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
142	device_printf(dev, " ");
143	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
144		printf("no media present");
145	else {
146		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
147		PRINT("HomePNA");
148	}
149	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
150	    BMCR_ISO);
151
152	printf("\n");
153
154#undef ADD
155#undef PRINT
156
157	MIIBUS_MEDIAINIT(sc->mii_dev);
158
159	return(0);
160}
161
162static int
163pnaphy_service(sc, mii, cmd)
164	struct mii_softc *sc;
165	struct mii_data *mii;
166	int cmd;
167{
168	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
169	int reg;
170
171	switch (cmd) {
172	case MII_POLLSTAT:
173		/*
174		 * If we're not polling our PHY instance, just return.
175		 */
176		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
177			return (0);
178		break;
179
180	case MII_MEDIACHG:
181		/*
182		 * If the media indicates a different PHY instance,
183		 * isolate ourselves.
184		 */
185		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
186			reg = PHY_READ(sc, MII_BMCR);
187			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
188			return (0);
189		}
190
191		/*
192		 * If the interface is not up, don't do anything.
193		 */
194		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
195			break;
196
197		switch (IFM_SUBTYPE(ife->ifm_media)) {
198		case IFM_AUTO:
199		case IFM_10_T:
200		case IFM_100_TX:
201		case IFM_100_T4:
202			return (EINVAL);
203		default:
204			/*
205			 * BMCR data is stored in the ifmedia entry.
206			 */
207			PHY_WRITE(sc, MII_ANAR,
208			    mii_anar(ife->ifm_media));
209			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
210		}
211		break;
212
213	case MII_TICK:
214		/*
215		 * If we're not currently selected, just return.
216		 */
217		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
218			return (0);
219		if (mii_phy_tick(sc) == EJUSTRETURN)
220			return (0);
221		break;
222	}
223
224	/* Update the media status. */
225	ukphy_status(sc);
226	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
227		mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
228
229	/* Callback if something changed. */
230	mii_phy_update(sc, cmd);
231	return (0);
232}
233