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