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