pnaphy.c revision 104094
166129Swpaul/*
266129Swpaul * Copyright (c) 2000 Berkeley Software Design, Inc.
366129Swpaul * Copyright (c) 1997, 1998, 1999, 2000
466129Swpaul *	Bill Paul <wpaul@osd.bsdi.com>.  All rights reserved.
566129Swpaul *
666129Swpaul * Redistribution and use in source and binary forms, with or without
766129Swpaul * modification, are permitted provided that the following conditions
866129Swpaul * are met:
966129Swpaul * 1. Redistributions of source code must retain the above copyright
1066129Swpaul *    notice, this list of conditions and the following disclaimer.
1166129Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1266129Swpaul *    notice, this list of conditions and the following disclaimer in the
1366129Swpaul *    documentation and/or other materials provided with the distribution.
1466129Swpaul * 3. All advertising materials mentioning features or use of this software
1566129Swpaul *    must display the following acknowledgement:
1666129Swpaul *	This product includes software developed by Bill Paul.
1766129Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1866129Swpaul *    may be used to endorse or promote products derived from this software
1966129Swpaul *    without specific prior written permission.
2066129Swpaul *
2166129Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2266129Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2366129Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2466129Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2566129Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2666129Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2766129Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2866129Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2966129Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3066129Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3166129Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3266129Swpaul *
3366129Swpaul * $FreeBSD: head/sys/dev/mii/pnaphy.c 104094 2002-09-28 17:15:38Z phk $
3466129Swpaul */
3566129Swpaul
3666129Swpaul/*
3766129Swpaul * driver for homePNA PHYs
3866129Swpaul * This is really just a stub that allows us to identify homePNA-based
3966129Swpaul * transceicers and display the link status. MII-based homePNA PHYs
4066129Swpaul * only support one media type and no autonegotiation. If we were
4166129Swpaul * really clever, we could tweak some of the vendor-specific registers
4266129Swpaul * to optimize the link.
4366129Swpaul */
4466129Swpaul
4566129Swpaul#include <sys/param.h>
4666129Swpaul#include <sys/systm.h>
4766129Swpaul#include <sys/kernel.h>
4866129Swpaul#include <sys/malloc.h>
4966129Swpaul#include <sys/socket.h>
5066129Swpaul#include <sys/errno.h>
5166129Swpaul#include <sys/module.h>
5266129Swpaul#include <sys/bus.h>
5366129Swpaul
5466129Swpaul#include <net/if.h>
5566129Swpaul#include <net/if_media.h>
5666129Swpaul
5766129Swpaul
5866129Swpaul#include <dev/mii/mii.h>
5966129Swpaul#include <dev/mii/miivar.h>
6066129Swpaul#include <dev/mii/miidevs.h>
6166129Swpaul
6266129Swpaul#include "miibus_if.h"
6366129Swpaul
6466129Swpaul#if !defined(lint)
6566129Swpaulstatic const char rcsid[] =
6666129Swpaul  "$FreeBSD: head/sys/dev/mii/pnaphy.c 104094 2002-09-28 17:15:38Z phk $";
6766129Swpaul#endif
6866129Swpaul
6992739Salfredstatic int pnaphy_probe		(device_t);
7092739Salfredstatic int pnaphy_attach	(device_t);
7166129Swpaul
7266129Swpaulstatic device_method_t pnaphy_methods[] = {
7366129Swpaul	/* device interface */
7466129Swpaul	DEVMETHOD(device_probe,		pnaphy_probe),
7566129Swpaul	DEVMETHOD(device_attach,	pnaphy_attach),
7695722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
7766129Swpaul	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
7866129Swpaul	{ 0, 0 }
7966129Swpaul};
8066129Swpaul
8166129Swpaulstatic devclass_t pnaphy_devclass;
8266129Swpaul
8366129Swpaulstatic driver_t pnaphy_driver = {
8466129Swpaul	"pnaphy",
8566129Swpaul	pnaphy_methods,
8666129Swpaul	sizeof(struct mii_softc)
8766129Swpaul};
8866129Swpaul
8966129SwpaulDRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
9066129Swpaul
9192739Salfredstatic int	pnaphy_service(struct mii_softc *, struct mii_data *,int);
9266129Swpaul
9366129Swpaulstatic int
9466129Swpaulpnaphy_probe(dev)
9566129Swpaul	device_t		dev;
9666129Swpaul{
9766129Swpaul
9866129Swpaul	struct mii_attach_args	*ma;
9966129Swpaul
10066129Swpaul	ma = device_get_ivars(dev);
10166129Swpaul
10266129Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
10366129Swpaul	    MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
10466129Swpaul		device_set_desc(dev, MII_STR_AMD_79c978);
10566129Swpaul		return(0);
10666129Swpaul	}
10766129Swpaul
10866129Swpaul	return(ENXIO);
10966129Swpaul}
11066129Swpaul
11166129Swpaulstatic int
11266129Swpaulpnaphy_attach(dev)
11366129Swpaul	device_t		dev;
11466129Swpaul{
11566129Swpaul	struct mii_softc *sc;
11666129Swpaul	struct mii_attach_args *ma;
11766129Swpaul	struct mii_data *mii;
11866129Swpaul	const char *sep = "";
11966129Swpaul
12066129Swpaul	sc = device_get_softc(dev);
12166129Swpaul	ma = device_get_ivars(dev);
12266129Swpaul	sc->mii_dev = device_get_parent(dev);
12366129Swpaul	mii = device_get_softc(sc->mii_dev);
12466129Swpaul	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
12566129Swpaul
12666129Swpaul	sc->mii_inst = mii->mii_instance;
12766129Swpaul	sc->mii_phy = ma->mii_phyno;
12866129Swpaul	sc->mii_service = pnaphy_service;
12966129Swpaul	sc->mii_pdata = mii;
13066129Swpaul
13166129Swpaul	mii->mii_instance++;
13266129Swpaul
13366129Swpaul	sc->mii_flags |= MIIF_NOISOLATE;
13466129Swpaul
13566129Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
13666129Swpaul#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
13766129Swpaul
13866129Swpaul	mii_phy_reset(sc);
13966129Swpaul
14066129Swpaul	sc->mii_capabilities =
14166129Swpaul	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
14266129Swpaul	device_printf(dev, " ");
14366129Swpaul	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
14466129Swpaul		printf("no media present");
14566129Swpaul	else {
14695702Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
14766129Swpaul		PRINT("HomePNA");
14866129Swpaul	}
14966129Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
15066129Swpaul	    BMCR_ISO);
15166129Swpaul
15266129Swpaul	printf("\n");
15366129Swpaul
15466129Swpaul#undef ADD
15566129Swpaul#undef PRINT
15666129Swpaul
15766129Swpaul	MIIBUS_MEDIAINIT(sc->mii_dev);
15866129Swpaul
15966129Swpaul	return(0);
16066129Swpaul}
16166129Swpaul
162104094Sphkstatic int
16366129Swpaulpnaphy_service(sc, mii, cmd)
16466129Swpaul	struct mii_softc *sc;
16566129Swpaul	struct mii_data *mii;
16666129Swpaul	int cmd;
16766129Swpaul{
16866129Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
16966129Swpaul	int reg;
17066129Swpaul
17166129Swpaul	switch (cmd) {
17266129Swpaul	case MII_POLLSTAT:
17366129Swpaul		/*
17466129Swpaul		 * If we're not polling our PHY instance, just return.
17566129Swpaul		 */
17666129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
17766129Swpaul			return (0);
17866129Swpaul		break;
17966129Swpaul
18066129Swpaul	case MII_MEDIACHG:
18166129Swpaul		/*
18266129Swpaul		 * If the media indicates a different PHY instance,
18366129Swpaul		 * isolate ourselves.
18466129Swpaul		 */
18566129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
18666129Swpaul			reg = PHY_READ(sc, MII_BMCR);
18766129Swpaul			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
18866129Swpaul			return (0);
18966129Swpaul		}
19066129Swpaul
19166129Swpaul		/*
19266129Swpaul		 * If the interface is not up, don't do anything.
19366129Swpaul		 */
19466129Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
19566129Swpaul			break;
19666129Swpaul
19766129Swpaul		switch (IFM_SUBTYPE(ife->ifm_media)) {
19866129Swpaul		case IFM_AUTO:
19966129Swpaul		case IFM_10_T:
20066129Swpaul		case IFM_100_TX:
20166129Swpaul		case IFM_100_T4:
20266129Swpaul			return (EINVAL);
20366129Swpaul		default:
20466129Swpaul			/*
20566129Swpaul			 * BMCR data is stored in the ifmedia entry.
20666129Swpaul			 */
20766129Swpaul			PHY_WRITE(sc, MII_ANAR,
20866129Swpaul			    mii_anar(ife->ifm_media));
20966129Swpaul			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
21066129Swpaul		}
21166129Swpaul		break;
21266129Swpaul
21366129Swpaul	case MII_TICK:
21466129Swpaul		/*
21566129Swpaul		 * If we're not currently selected, just return.
21666129Swpaul		 */
21766129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
21866129Swpaul			return (0);
21984145Sjlemon		if (mii_phy_tick(sc) == EJUSTRETURN)
22066129Swpaul			return (0);
22166129Swpaul		break;
22266129Swpaul	}
22366129Swpaul
22466129Swpaul	/* Update the media status. */
22566129Swpaul	ukphy_status(sc);
22666129Swpaul	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
22795702Sphk		mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
22866129Swpaul
22966129Swpaul	/* Callback if something changed. */
23084145Sjlemon	mii_phy_update(sc, cmd);
23166129Swpaul	return (0);
23266129Swpaul}
233