pnaphy.c revision 119418
1147191Sjkoshy/*
2147191Sjkoshy * Copyright (c) 2000 Berkeley Software Design, Inc.
3147191Sjkoshy * Copyright (c) 1997, 1998, 1999, 2000
4147191Sjkoshy *	Bill Paul <wpaul@osd.bsdi.com>.  All rights reserved.
5147191Sjkoshy *
6147191Sjkoshy * Redistribution and use in source and binary forms, with or without
7147191Sjkoshy * modification, are permitted provided that the following conditions
8147191Sjkoshy * are met:
9147191Sjkoshy * 1. Redistributions of source code must retain the above copyright
10147191Sjkoshy *    notice, this list of conditions and the following disclaimer.
11147191Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
12147191Sjkoshy *    notice, this list of conditions and the following disclaimer in the
13147191Sjkoshy *    documentation and/or other materials provided with the distribution.
14147191Sjkoshy * 3. All advertising materials mentioning features or use of this software
15147191Sjkoshy *    must display the following acknowledgement:
16147191Sjkoshy *	This product includes software developed by Bill Paul.
17147191Sjkoshy * 4. Neither the name of the author nor the names of any co-contributors
18147191Sjkoshy *    may be used to endorse or promote products derived from this software
19147191Sjkoshy *    without specific prior written permission.
20147191Sjkoshy *
21147191Sjkoshy * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22147191Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23147191Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24147191Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25147191Sjkoshy * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26147191Sjkoshy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27147191Sjkoshy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28147191Sjkoshy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29147191Sjkoshy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30147191Sjkoshy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31147191Sjkoshy * THE POSSIBILITY OF SUCH DAMAGE.
32249069Ssbruno */
33196739Sgnn
34196739Sgnn#include <sys/cdefs.h>
35196739Sgnn__FBSDID("$FreeBSD: head/sys/dev/mii/pnaphy.c 119418 2003-08-24 17:55:58Z obrien $");
36147191Sjkoshy
37196739Sgnn/*
38196739Sgnn * driver for homePNA PHYs
39196739Sgnn * This is really just a stub that allows us to identify homePNA-based
40196739Sgnn * transceicers and display the link status. MII-based homePNA PHYs
41196739Sgnn * only support one media type and no autonegotiation. If we were
42196739Sgnn * really clever, we could tweak some of the vendor-specific registers
43196739Sgnn * to optimize the link.
44196739Sgnn */
45185363Sjkoshy
46147191Sjkoshy#include <sys/cdefs.h>
47147191Sjkoshy__FBSDID("$FreeBSD: head/sys/dev/mii/pnaphy.c 119418 2003-08-24 17:55:58Z obrien $");
48147191Sjkoshy
49147191Sjkoshy#include <sys/param.h>
50147191Sjkoshy#include <sys/systm.h>
51147191Sjkoshy#include <sys/kernel.h>
52147191Sjkoshy#include <sys/socket.h>
53147191Sjkoshy#include <sys/errno.h>
54183725Sjkoshy#include <sys/module.h>
55183725Sjkoshy#include <sys/bus.h>
56183725Sjkoshy
57183725Sjkoshy#include <net/if.h>
58183725Sjkoshy#include <net/if_media.h>
59183725Sjkoshy
60183725Sjkoshy
61183725Sjkoshy#include <dev/mii/mii.h>
62183725Sjkoshy#include <dev/mii/miivar.h>
63183725Sjkoshy#include "miidevs.h"
64183725Sjkoshy
65183725Sjkoshy#include "miibus_if.h"
66183725Sjkoshy
67183725Sjkoshystatic int pnaphy_probe(device_t);
68183725Sjkoshystatic int pnaphy_attach(device_t);
69183725Sjkoshy
70183725Sjkoshystatic device_method_t pnaphy_methods[] = {
71183725Sjkoshy	/* device interface */
72183725Sjkoshy	DEVMETHOD(device_probe,		pnaphy_probe),
73183725Sjkoshy	DEVMETHOD(device_attach,	pnaphy_attach),
74183725Sjkoshy	DEVMETHOD(device_detach,	mii_phy_detach),
75183725Sjkoshy	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
76183725Sjkoshy	{ 0, 0 }
77183725Sjkoshy};
78147191Sjkoshy
79147191Sjkoshystatic devclass_t pnaphy_devclass;
80147191Sjkoshy
81147191Sjkoshystatic driver_t pnaphy_driver = {
82185363Sjkoshy	"pnaphy",
83147191Sjkoshy	pnaphy_methods,
84147191Sjkoshy	sizeof(struct mii_softc)
85147191Sjkoshy};
86147191Sjkoshy
87147191SjkoshyDRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
88183725Sjkoshy
89183725Sjkoshystatic int	pnaphy_service(struct mii_softc *, struct mii_data *,int);
90183725Sjkoshy
91183725Sjkoshystatic int
92183725Sjkoshypnaphy_probe(dev)
93183725Sjkoshy	device_t		dev;
94183725Sjkoshy{
95183725Sjkoshy
96183725Sjkoshy	struct mii_attach_args	*ma;
97183725Sjkoshy
98183725Sjkoshy	ma = device_get_ivars(dev);
99183725Sjkoshy
100183725Sjkoshy	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
101183725Sjkoshy	    MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
102183725Sjkoshy		device_set_desc(dev, MII_STR_AMD_79c978);
103183725Sjkoshy		return(0);
104183725Sjkoshy	}
105183725Sjkoshy
106183725Sjkoshy	return(ENXIO);
107183725Sjkoshy}
108183725Sjkoshy
109183725Sjkoshystatic int
110183725Sjkoshypnaphy_attach(dev)
111183725Sjkoshy	device_t		dev;
112183725Sjkoshy{
113183725Sjkoshy	struct mii_softc *sc;
114183725Sjkoshy	struct mii_attach_args *ma;
115183725Sjkoshy	struct mii_data *mii;
116183725Sjkoshy	const char *sep = "";
117183725Sjkoshy
118183725Sjkoshy	sc = device_get_softc(dev);
119183725Sjkoshy	ma = device_get_ivars(dev);
120183725Sjkoshy	sc->mii_dev = device_get_parent(dev);
121183725Sjkoshy	mii = device_get_softc(sc->mii_dev);
122183725Sjkoshy	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
123183725Sjkoshy
124183725Sjkoshy	sc->mii_inst = mii->mii_instance;
125183725Sjkoshy	sc->mii_phy = ma->mii_phyno;
126183725Sjkoshy	sc->mii_service = pnaphy_service;
127183725Sjkoshy	sc->mii_pdata = mii;
128183725Sjkoshy
129183725Sjkoshy	mii->mii_instance++;
130183725Sjkoshy
131183725Sjkoshy	sc->mii_flags |= MIIF_NOISOLATE;
132183725Sjkoshy
133183725Sjkoshy#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
134147191Sjkoshy#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
135147191Sjkoshy
136147191Sjkoshy	mii_phy_reset(sc);
137147191Sjkoshy
138147191Sjkoshy	sc->mii_capabilities =
139147191Sjkoshy	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
140183725Sjkoshy	device_printf(dev, " ");
141183725Sjkoshy	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
142183725Sjkoshy		printf("no media present");
143183725Sjkoshy	else {
144183725Sjkoshy		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
145183725Sjkoshy		PRINT("HomePNA");
146183725Sjkoshy	}
147183725Sjkoshy	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
148183725Sjkoshy	    BMCR_ISO);
149183725Sjkoshy
150183725Sjkoshy	printf("\n");
151183725Sjkoshy
152183725Sjkoshy#undef ADD
153183725Sjkoshy#undef PRINT
154183725Sjkoshy
155183725Sjkoshy	MIIBUS_MEDIAINIT(sc->mii_dev);
156183725Sjkoshy
157183725Sjkoshy	return(0);
158183725Sjkoshy}
159183725Sjkoshy
160183725Sjkoshystatic int
161183725Sjkoshypnaphy_service(sc, mii, cmd)
162183725Sjkoshy	struct mii_softc *sc;
163183725Sjkoshy	struct mii_data *mii;
164183725Sjkoshy	int cmd;
165183725Sjkoshy{
166183725Sjkoshy	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
167183725Sjkoshy	int reg;
168183725Sjkoshy
169183725Sjkoshy	switch (cmd) {
170183725Sjkoshy	case MII_POLLSTAT:
171183725Sjkoshy		/*
172183725Sjkoshy		 * If we're not polling our PHY instance, just return.
173183725Sjkoshy		 */
174183725Sjkoshy		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
175183725Sjkoshy			return (0);
176183725Sjkoshy		break;
177183725Sjkoshy
178183725Sjkoshy	case MII_MEDIACHG:
179183725Sjkoshy		/*
180183725Sjkoshy		 * If the media indicates a different PHY instance,
181183725Sjkoshy		 * isolate ourselves.
182183725Sjkoshy		 */
183183725Sjkoshy		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
184183725Sjkoshy			reg = PHY_READ(sc, MII_BMCR);
185183725Sjkoshy			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
186183725Sjkoshy			return (0);
187183725Sjkoshy		}
188183725Sjkoshy
189183725Sjkoshy		/*
190183725Sjkoshy		 * If the interface is not up, don't do anything.
191183725Sjkoshy		 */
192183725Sjkoshy		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
193183725Sjkoshy			break;
194183725Sjkoshy
195183725Sjkoshy		switch (IFM_SUBTYPE(ife->ifm_media)) {
196183725Sjkoshy		case IFM_AUTO:
197183725Sjkoshy		case IFM_10_T:
198183725Sjkoshy		case IFM_100_TX:
199183725Sjkoshy		case IFM_100_T4:
200183725Sjkoshy			return (EINVAL);
201183725Sjkoshy		default:
202183725Sjkoshy			/*
203183725Sjkoshy			 * BMCR data is stored in the ifmedia entry.
204183725Sjkoshy			 */
205183725Sjkoshy			PHY_WRITE(sc, MII_ANAR,
206183725Sjkoshy			    mii_anar(ife->ifm_media));
207183725Sjkoshy			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
208183725Sjkoshy		}
209183725Sjkoshy		break;
210183725Sjkoshy
211183725Sjkoshy	case MII_TICK:
212183725Sjkoshy		/*
213183725Sjkoshy		 * If we're not currently selected, just return.
214183725Sjkoshy		 */
215183725Sjkoshy		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
216183725Sjkoshy			return (0);
217183725Sjkoshy		if (mii_phy_tick(sc) == EJUSTRETURN)
218183725Sjkoshy			return (0);
219183725Sjkoshy		break;
220183725Sjkoshy	}
221183725Sjkoshy
222183725Sjkoshy	/* Update the media status. */
223183725Sjkoshy	ukphy_status(sc);
224183725Sjkoshy	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
225183725Sjkoshy		mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
226183725Sjkoshy
227183725Sjkoshy	/* Callback if something changed. */
228183725Sjkoshy	mii_phy_update(sc, cmd);
229183725Sjkoshy	return (0);
230183725Sjkoshy}
231183725Sjkoshy