pnaphy.c revision 95702
190926Snectar/*
2233294Sstas * Copyright (c) 2000 Berkeley Software Design, Inc.
3233294Sstas * Copyright (c) 1997, 1998, 1999, 2000
4233294Sstas *	Bill Paul <wpaul@osd.bsdi.com>.  All rights reserved.
590926Snectar *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
990926Snectar * 1. Redistributions of source code must retain the above copyright
10233294Sstas *    notice, this list of conditions and the following disclaimer.
11233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
1290926Snectar *    notice, this list of conditions and the following disclaimer in the
13233294Sstas *    documentation and/or other materials provided with the distribution.
14233294Sstas * 3. All advertising materials mentioning features or use of this software
15233294Sstas *    must display the following acknowledgement:
1690926Snectar *	This product includes software developed by Bill Paul.
17233294Sstas * 4. Neither the name of the author nor the names of any co-contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2090926Snectar *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25233294Sstas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26233294Sstas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27233294Sstas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28233294Sstas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29233294Sstas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30233294Sstas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31233294Sstas * THE POSSIBILITY OF SUCH DAMAGE.
3290926Snectar *
3390926Snectar * $FreeBSD: head/sys/dev/mii/pnaphy.c 95702 2002-04-29 05:32:44Z phk $
3490926Snectar */
3590926Snectar
36233294Sstas/*
3790926Snectar * driver for homePNA PHYs
3890926Snectar * This is really just a stub that allows us to identify homePNA-based
39233294Sstas * transceicers and display the link status. MII-based homePNA PHYs
4090926Snectar * only support one media type and no autonegotiation. If we were
4190926Snectar * really clever, we could tweak some of the vendor-specific registers
4290926Snectar * to optimize the link.
4390926Snectar */
4490926Snectar
4590926Snectar#include <sys/param.h>
4690926Snectar#include <sys/systm.h>
4790926Snectar#include <sys/kernel.h>
4890926Snectar#include <sys/malloc.h>
4990926Snectar#include <sys/socket.h>
50178825Sdfr#include <sys/errno.h>
5190926Snectar#include <sys/module.h>
5290926Snectar#include <sys/bus.h>
5390926Snectar
5490926Snectar#include <net/if.h>
5590926Snectar#include <net/if_media.h>
5690926Snectar
57178825Sdfr
5890926Snectar#include <dev/mii/mii.h>
5990926Snectar#include <dev/mii/miivar.h>
6090926Snectar#include <dev/mii/miidevs.h>
6190926Snectar
6290926Snectar#include "miibus_if.h"
6390926Snectar
6490926Snectar#if !defined(lint)
6590926Snectarstatic const char rcsid[] =
6690926Snectar  "$FreeBSD: head/sys/dev/mii/pnaphy.c 95702 2002-04-29 05:32:44Z phk $";
6790926Snectar#endif
6890926Snectar
6990926Snectarstatic int pnaphy_probe		(device_t);
7090926Snectarstatic int pnaphy_attach	(device_t);
7190926Snectarstatic int pnaphy_detach	(device_t);
7290926Snectar
7390926Snectarstatic device_method_t pnaphy_methods[] = {
7490926Snectar	/* device interface */
7590926Snectar	DEVMETHOD(device_probe,		pnaphy_probe),
7690926Snectar	DEVMETHOD(device_attach,	pnaphy_attach),
7790926Snectar	DEVMETHOD(device_detach,	pnaphy_detach),
78178825Sdfr	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
79178825Sdfr	{ 0, 0 }
8090926Snectar};
8190926Snectar
8290926Snectarstatic devclass_t pnaphy_devclass;
8390926Snectar
8490926Snectarstatic driver_t pnaphy_driver = {
8590926Snectar	"pnaphy",
8690926Snectar	pnaphy_methods,
8790926Snectar	sizeof(struct mii_softc)
8890926Snectar};
8990926Snectar
9090926SnectarDRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
9190926Snectar
92233294Sstasstatic int	pnaphy_service(struct mii_softc *, struct mii_data *,int);
93233294Sstas
94233294Sstasstatic int
95233294Sstaspnaphy_probe(dev)
96233294Sstas	device_t		dev;
97233294Sstas{
98233294Sstas
99233294Sstas	struct mii_attach_args	*ma;
100233294Sstas
10190926Snectar	ma = device_get_ivars(dev);
10290926Snectar
10390926Snectar	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
10490926Snectar	    MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
10590926Snectar		device_set_desc(dev, MII_STR_AMD_79c978);
10690926Snectar		return(0);
10790926Snectar	}
10890926Snectar
10990926Snectar	return(ENXIO);
11090926Snectar}
111178825Sdfr
11290926Snectarstatic int
11390926Snectarpnaphy_attach(dev)
114	device_t		dev;
115{
116	struct mii_softc *sc;
117	struct mii_attach_args *ma;
118	struct mii_data *mii;
119	const char *sep = "";
120
121	sc = device_get_softc(dev);
122	ma = device_get_ivars(dev);
123	sc->mii_dev = device_get_parent(dev);
124	mii = device_get_softc(sc->mii_dev);
125	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
126
127	sc->mii_inst = mii->mii_instance;
128	sc->mii_phy = ma->mii_phyno;
129	sc->mii_service = pnaphy_service;
130	sc->mii_pdata = mii;
131
132	mii->mii_instance++;
133
134	sc->mii_flags |= MIIF_NOISOLATE;
135
136#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
137#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
138
139	mii_phy_reset(sc);
140
141	sc->mii_capabilities =
142	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
143	device_printf(dev, " ");
144	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
145		printf("no media present");
146	else {
147		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
148		PRINT("HomePNA");
149	}
150	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
151	    BMCR_ISO);
152
153	printf("\n");
154
155#undef ADD
156#undef PRINT
157
158	MIIBUS_MEDIAINIT(sc->mii_dev);
159
160	return(0);
161}
162
163static int pnaphy_detach(dev)
164	device_t		dev;
165{
166	struct mii_softc *sc;
167	struct mii_data *mii;
168
169	sc = device_get_softc(dev);
170	mii = device_get_softc(device_get_parent(dev));
171	mii_phy_auto_stop(sc);
172	sc->mii_dev = NULL;
173	LIST_REMOVE(sc, mii_list);
174
175	return(0);
176}
177
178int
179pnaphy_service(sc, mii, cmd)
180	struct mii_softc *sc;
181	struct mii_data *mii;
182	int cmd;
183{
184	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
185	int reg;
186
187	switch (cmd) {
188	case MII_POLLSTAT:
189		/*
190		 * If we're not polling our PHY instance, just return.
191		 */
192		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
193			return (0);
194		break;
195
196	case MII_MEDIACHG:
197		/*
198		 * If the media indicates a different PHY instance,
199		 * isolate ourselves.
200		 */
201		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
202			reg = PHY_READ(sc, MII_BMCR);
203			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
204			return (0);
205		}
206
207		/*
208		 * If the interface is not up, don't do anything.
209		 */
210		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
211			break;
212
213		switch (IFM_SUBTYPE(ife->ifm_media)) {
214		case IFM_AUTO:
215		case IFM_10_T:
216		case IFM_100_TX:
217		case IFM_100_T4:
218			return (EINVAL);
219		default:
220			/*
221			 * BMCR data is stored in the ifmedia entry.
222			 */
223			PHY_WRITE(sc, MII_ANAR,
224			    mii_anar(ife->ifm_media));
225			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
226		}
227		break;
228
229	case MII_TICK:
230		/*
231		 * If we're not currently selected, just return.
232		 */
233		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
234			return (0);
235		if (mii_phy_tick(sc) == EJUSTRETURN)
236			return (0);
237		break;
238	}
239
240	/* Update the media status. */
241	ukphy_status(sc);
242	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
243		mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
244
245	/* Callback if something changed. */
246	mii_phy_update(sc, cmd);
247	return (0);
248}
249