pnaphy.c revision 150763
1139749Simp/*-
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
34119418Sobrien#include <sys/cdefs.h>
35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/pnaphy.c 150763 2005-09-30 19:39:27Z imp $");
36119418Sobrien
3766129Swpaul/*
3866129Swpaul * driver for homePNA PHYs
3966129Swpaul * This is really just a stub that allows us to identify homePNA-based
4066129Swpaul * transceicers and display the link status. MII-based homePNA PHYs
4166129Swpaul * only support one media type and no autonegotiation. If we were
4266129Swpaul * really clever, we could tweak some of the vendor-specific registers
4366129Swpaul * to optimize the link.
4466129Swpaul */
4566129Swpaul
4666129Swpaul#include <sys/param.h>
4766129Swpaul#include <sys/systm.h>
4866129Swpaul#include <sys/kernel.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>
60109514Sobrien#include "miidevs.h"
6166129Swpaul
6266129Swpaul#include "miibus_if.h"
6366129Swpaul
64105135Salfredstatic int pnaphy_probe(device_t);
65105135Salfredstatic int pnaphy_attach(device_t);
6666129Swpaul
6766129Swpaulstatic device_method_t pnaphy_methods[] = {
6866129Swpaul	/* device interface */
6966129Swpaul	DEVMETHOD(device_probe,		pnaphy_probe),
7066129Swpaul	DEVMETHOD(device_attach,	pnaphy_attach),
7195722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
7266129Swpaul	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
7366129Swpaul	{ 0, 0 }
7466129Swpaul};
7566129Swpaul
7666129Swpaulstatic devclass_t pnaphy_devclass;
7766129Swpaul
7866129Swpaulstatic driver_t pnaphy_driver = {
7966129Swpaul	"pnaphy",
8066129Swpaul	pnaphy_methods,
8166129Swpaul	sizeof(struct mii_softc)
8266129Swpaul};
8366129Swpaul
8466129SwpaulDRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0);
8566129Swpaul
8692739Salfredstatic int	pnaphy_service(struct mii_softc *, struct mii_data *,int);
8766129Swpaul
8866129Swpaulstatic int
89150763Simppnaphy_probe(device_t dev)
9066129Swpaul{
9166129Swpaul
9266129Swpaul	struct mii_attach_args	*ma;
9366129Swpaul
9466129Swpaul	ma = device_get_ivars(dev);
9566129Swpaul
9666129Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD &&
9766129Swpaul	    MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) {
9866129Swpaul		device_set_desc(dev, MII_STR_AMD_79c978);
9966129Swpaul		return(0);
10066129Swpaul	}
10166129Swpaul
10266129Swpaul	return(ENXIO);
10366129Swpaul}
10466129Swpaul
10566129Swpaulstatic int
106150763Simppnaphy_attach(device_t dev)
10766129Swpaul{
10866129Swpaul	struct mii_softc *sc;
10966129Swpaul	struct mii_attach_args *ma;
11066129Swpaul	struct mii_data *mii;
11166129Swpaul	const char *sep = "";
11266129Swpaul
11366129Swpaul	sc = device_get_softc(dev);
11466129Swpaul	ma = device_get_ivars(dev);
11566129Swpaul	sc->mii_dev = device_get_parent(dev);
11666129Swpaul	mii = device_get_softc(sc->mii_dev);
11766129Swpaul	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
11866129Swpaul
11966129Swpaul	sc->mii_inst = mii->mii_instance;
12066129Swpaul	sc->mii_phy = ma->mii_phyno;
12166129Swpaul	sc->mii_service = pnaphy_service;
12266129Swpaul	sc->mii_pdata = mii;
12366129Swpaul
12466129Swpaul	mii->mii_instance++;
12566129Swpaul
12666129Swpaul	sc->mii_flags |= MIIF_NOISOLATE;
12766129Swpaul
12866129Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
12966129Swpaul#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
13066129Swpaul
13166129Swpaul	mii_phy_reset(sc);
13266129Swpaul
13366129Swpaul	sc->mii_capabilities =
13466129Swpaul	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
13566129Swpaul	device_printf(dev, " ");
13666129Swpaul	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
13766129Swpaul		printf("no media present");
13866129Swpaul	else {
13995702Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0);
14066129Swpaul		PRINT("HomePNA");
14166129Swpaul	}
14266129Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
14366129Swpaul	    BMCR_ISO);
14466129Swpaul
14566129Swpaul	printf("\n");
14666129Swpaul
14766129Swpaul#undef ADD
14866129Swpaul#undef PRINT
14966129Swpaul
15066129Swpaul	MIIBUS_MEDIAINIT(sc->mii_dev);
15166129Swpaul
15266129Swpaul	return(0);
15366129Swpaul}
15466129Swpaul
155104094Sphkstatic int
156150763Simppnaphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
15766129Swpaul{
15866129Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
15966129Swpaul	int reg;
16066129Swpaul
16166129Swpaul	switch (cmd) {
16266129Swpaul	case MII_POLLSTAT:
16366129Swpaul		/*
16466129Swpaul		 * If we're not polling our PHY instance, just return.
16566129Swpaul		 */
16666129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
16766129Swpaul			return (0);
16866129Swpaul		break;
16966129Swpaul
17066129Swpaul	case MII_MEDIACHG:
17166129Swpaul		/*
17266129Swpaul		 * If the media indicates a different PHY instance,
17366129Swpaul		 * isolate ourselves.
17466129Swpaul		 */
17566129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
17666129Swpaul			reg = PHY_READ(sc, MII_BMCR);
17766129Swpaul			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
17866129Swpaul			return (0);
17966129Swpaul		}
18066129Swpaul
18166129Swpaul		/*
18266129Swpaul		 * If the interface is not up, don't do anything.
18366129Swpaul		 */
18466129Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
18566129Swpaul			break;
18666129Swpaul
18766129Swpaul		switch (IFM_SUBTYPE(ife->ifm_media)) {
18866129Swpaul		case IFM_AUTO:
18966129Swpaul		case IFM_10_T:
19066129Swpaul		case IFM_100_TX:
19166129Swpaul		case IFM_100_T4:
19266129Swpaul			return (EINVAL);
19366129Swpaul		default:
19466129Swpaul			/*
19566129Swpaul			 * BMCR data is stored in the ifmedia entry.
19666129Swpaul			 */
19766129Swpaul			PHY_WRITE(sc, MII_ANAR,
19866129Swpaul			    mii_anar(ife->ifm_media));
19966129Swpaul			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
20066129Swpaul		}
20166129Swpaul		break;
20266129Swpaul
20366129Swpaul	case MII_TICK:
20466129Swpaul		/*
20566129Swpaul		 * If we're not currently selected, just return.
20666129Swpaul		 */
20766129Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
20866129Swpaul			return (0);
20984145Sjlemon		if (mii_phy_tick(sc) == EJUSTRETURN)
21066129Swpaul			return (0);
21166129Swpaul		break;
21266129Swpaul	}
21366129Swpaul
21466129Swpaul	/* Update the media status. */
21566129Swpaul	ukphy_status(sc);
21666129Swpaul	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
21795702Sphk		mii->mii_media_active = IFM_ETHER|IFM_HPNA_1;
21866129Swpaul
21966129Swpaul	/* Callback if something changed. */
22084145Sjlemon	mii_phy_update(sc, cmd);
22166129Swpaul	return (0);
22266129Swpaul}
223