pnaphy.c revision 119418
1147191Sjkoshy/* 2147191Sjkoshy * Copyright (c) 2000 Berkeley Software Design, Inc. 3147191Sjkoshy * Copyright (c) 1997, 1998, 1999, 2000 4147191Sjkoshy * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved. 5147191Sjkoshy * 6147191Sjkoshy * Redistribution and use in source and binary forms, with or without 7147191Sjkoshy * modification, are permitted provided that the following conditions 8147191Sjkoshy * are met: 9147191Sjkoshy * 1. Redistributions of source code must retain the above copyright 10147191Sjkoshy * notice, this list of conditions and the following disclaimer. 11147191Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 12147191Sjkoshy * notice, this list of conditions and the following disclaimer in the 13147191Sjkoshy * documentation and/or other materials provided with the distribution. 14147191Sjkoshy * 3. All advertising materials mentioning features or use of this software 15147191Sjkoshy * must display the following acknowledgement: 16147191Sjkoshy * This product includes software developed by Bill Paul. 17147191Sjkoshy * 4. Neither the name of the author nor the names of any co-contributors 18147191Sjkoshy * may be used to endorse or promote products derived from this software 19147191Sjkoshy * without specific prior written permission. 20147191Sjkoshy * 21147191Sjkoshy * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22147191Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23147191Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24147191Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25147191Sjkoshy * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26147191Sjkoshy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27147191Sjkoshy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28147191Sjkoshy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29147191Sjkoshy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30147191Sjkoshy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31147191Sjkoshy * THE POSSIBILITY OF SUCH DAMAGE. 32249069Ssbruno */ 33196739Sgnn 34196739Sgnn#include <sys/cdefs.h> 35196739Sgnn__FBSDID("$FreeBSD: head/sys/dev/mii/pnaphy.c 119418 2003-08-24 17:55:58Z obrien $"); 36147191Sjkoshy 37196739Sgnn/* 38196739Sgnn * driver for homePNA PHYs 39196739Sgnn * This is really just a stub that allows us to identify homePNA-based 40196739Sgnn * transceicers and display the link status. MII-based homePNA PHYs 41196739Sgnn * only support one media type and no autonegotiation. If we were 42196739Sgnn * really clever, we could tweak some of the vendor-specific registers 43196739Sgnn * to optimize the link. 44196739Sgnn */ 45185363Sjkoshy 46147191Sjkoshy#include <sys/cdefs.h> 47147191Sjkoshy__FBSDID("$FreeBSD: head/sys/dev/mii/pnaphy.c 119418 2003-08-24 17:55:58Z obrien $"); 48147191Sjkoshy 49147191Sjkoshy#include <sys/param.h> 50147191Sjkoshy#include <sys/systm.h> 51147191Sjkoshy#include <sys/kernel.h> 52147191Sjkoshy#include <sys/socket.h> 53147191Sjkoshy#include <sys/errno.h> 54183725Sjkoshy#include <sys/module.h> 55183725Sjkoshy#include <sys/bus.h> 56183725Sjkoshy 57183725Sjkoshy#include <net/if.h> 58183725Sjkoshy#include <net/if_media.h> 59183725Sjkoshy 60183725Sjkoshy 61183725Sjkoshy#include <dev/mii/mii.h> 62183725Sjkoshy#include <dev/mii/miivar.h> 63183725Sjkoshy#include "miidevs.h" 64183725Sjkoshy 65183725Sjkoshy#include "miibus_if.h" 66183725Sjkoshy 67183725Sjkoshystatic int pnaphy_probe(device_t); 68183725Sjkoshystatic int pnaphy_attach(device_t); 69183725Sjkoshy 70183725Sjkoshystatic device_method_t pnaphy_methods[] = { 71183725Sjkoshy /* device interface */ 72183725Sjkoshy DEVMETHOD(device_probe, pnaphy_probe), 73183725Sjkoshy DEVMETHOD(device_attach, pnaphy_attach), 74183725Sjkoshy DEVMETHOD(device_detach, mii_phy_detach), 75183725Sjkoshy DEVMETHOD(device_shutdown, bus_generic_shutdown), 76183725Sjkoshy { 0, 0 } 77183725Sjkoshy}; 78147191Sjkoshy 79147191Sjkoshystatic devclass_t pnaphy_devclass; 80147191Sjkoshy 81147191Sjkoshystatic driver_t pnaphy_driver = { 82185363Sjkoshy "pnaphy", 83147191Sjkoshy pnaphy_methods, 84147191Sjkoshy sizeof(struct mii_softc) 85147191Sjkoshy}; 86147191Sjkoshy 87147191SjkoshyDRIVER_MODULE(pnaphy, miibus, pnaphy_driver, pnaphy_devclass, 0, 0); 88183725Sjkoshy 89183725Sjkoshystatic int pnaphy_service(struct mii_softc *, struct mii_data *,int); 90183725Sjkoshy 91183725Sjkoshystatic int 92183725Sjkoshypnaphy_probe(dev) 93183725Sjkoshy device_t dev; 94183725Sjkoshy{ 95183725Sjkoshy 96183725Sjkoshy struct mii_attach_args *ma; 97183725Sjkoshy 98183725Sjkoshy ma = device_get_ivars(dev); 99183725Sjkoshy 100183725Sjkoshy if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_AMD && 101183725Sjkoshy MII_MODEL(ma->mii_id2) == MII_MODEL_AMD_79c978) { 102183725Sjkoshy device_set_desc(dev, MII_STR_AMD_79c978); 103183725Sjkoshy return(0); 104183725Sjkoshy } 105183725Sjkoshy 106183725Sjkoshy return(ENXIO); 107183725Sjkoshy} 108183725Sjkoshy 109183725Sjkoshystatic int 110183725Sjkoshypnaphy_attach(dev) 111183725Sjkoshy device_t dev; 112183725Sjkoshy{ 113183725Sjkoshy struct mii_softc *sc; 114183725Sjkoshy struct mii_attach_args *ma; 115183725Sjkoshy struct mii_data *mii; 116183725Sjkoshy const char *sep = ""; 117183725Sjkoshy 118183725Sjkoshy sc = device_get_softc(dev); 119183725Sjkoshy ma = device_get_ivars(dev); 120183725Sjkoshy sc->mii_dev = device_get_parent(dev); 121183725Sjkoshy mii = device_get_softc(sc->mii_dev); 122183725Sjkoshy LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 123183725Sjkoshy 124183725Sjkoshy sc->mii_inst = mii->mii_instance; 125183725Sjkoshy sc->mii_phy = ma->mii_phyno; 126183725Sjkoshy sc->mii_service = pnaphy_service; 127183725Sjkoshy sc->mii_pdata = mii; 128183725Sjkoshy 129183725Sjkoshy mii->mii_instance++; 130183725Sjkoshy 131183725Sjkoshy sc->mii_flags |= MIIF_NOISOLATE; 132183725Sjkoshy 133183725Sjkoshy#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 134147191Sjkoshy#define PRINT(s) printf("%s%s", sep, s); sep = ", " 135147191Sjkoshy 136147191Sjkoshy mii_phy_reset(sc); 137147191Sjkoshy 138147191Sjkoshy sc->mii_capabilities = 139147191Sjkoshy PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 140183725Sjkoshy device_printf(dev, " "); 141183725Sjkoshy if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 142183725Sjkoshy printf("no media present"); 143183725Sjkoshy else { 144183725Sjkoshy ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0); 145183725Sjkoshy PRINT("HomePNA"); 146183725Sjkoshy } 147183725Sjkoshy ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 148183725Sjkoshy BMCR_ISO); 149183725Sjkoshy 150183725Sjkoshy printf("\n"); 151183725Sjkoshy 152183725Sjkoshy#undef ADD 153183725Sjkoshy#undef PRINT 154183725Sjkoshy 155183725Sjkoshy MIIBUS_MEDIAINIT(sc->mii_dev); 156183725Sjkoshy 157183725Sjkoshy return(0); 158183725Sjkoshy} 159183725Sjkoshy 160183725Sjkoshystatic int 161183725Sjkoshypnaphy_service(sc, mii, cmd) 162183725Sjkoshy struct mii_softc *sc; 163183725Sjkoshy struct mii_data *mii; 164183725Sjkoshy int cmd; 165183725Sjkoshy{ 166183725Sjkoshy struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 167183725Sjkoshy int reg; 168183725Sjkoshy 169183725Sjkoshy switch (cmd) { 170183725Sjkoshy case MII_POLLSTAT: 171183725Sjkoshy /* 172183725Sjkoshy * If we're not polling our PHY instance, just return. 173183725Sjkoshy */ 174183725Sjkoshy if (IFM_INST(ife->ifm_media) != sc->mii_inst) 175183725Sjkoshy return (0); 176183725Sjkoshy break; 177183725Sjkoshy 178183725Sjkoshy case MII_MEDIACHG: 179183725Sjkoshy /* 180183725Sjkoshy * If the media indicates a different PHY instance, 181183725Sjkoshy * isolate ourselves. 182183725Sjkoshy */ 183183725Sjkoshy if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 184183725Sjkoshy reg = PHY_READ(sc, MII_BMCR); 185183725Sjkoshy PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 186183725Sjkoshy return (0); 187183725Sjkoshy } 188183725Sjkoshy 189183725Sjkoshy /* 190183725Sjkoshy * If the interface is not up, don't do anything. 191183725Sjkoshy */ 192183725Sjkoshy if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 193183725Sjkoshy break; 194183725Sjkoshy 195183725Sjkoshy switch (IFM_SUBTYPE(ife->ifm_media)) { 196183725Sjkoshy case IFM_AUTO: 197183725Sjkoshy case IFM_10_T: 198183725Sjkoshy case IFM_100_TX: 199183725Sjkoshy case IFM_100_T4: 200183725Sjkoshy return (EINVAL); 201183725Sjkoshy default: 202183725Sjkoshy /* 203183725Sjkoshy * BMCR data is stored in the ifmedia entry. 204183725Sjkoshy */ 205183725Sjkoshy PHY_WRITE(sc, MII_ANAR, 206183725Sjkoshy mii_anar(ife->ifm_media)); 207183725Sjkoshy PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 208183725Sjkoshy } 209183725Sjkoshy break; 210183725Sjkoshy 211183725Sjkoshy case MII_TICK: 212183725Sjkoshy /* 213183725Sjkoshy * If we're not currently selected, just return. 214183725Sjkoshy */ 215183725Sjkoshy if (IFM_INST(ife->ifm_media) != sc->mii_inst) 216183725Sjkoshy return (0); 217183725Sjkoshy if (mii_phy_tick(sc) == EJUSTRETURN) 218183725Sjkoshy return (0); 219183725Sjkoshy break; 220183725Sjkoshy } 221183725Sjkoshy 222183725Sjkoshy /* Update the media status. */ 223183725Sjkoshy ukphy_status(sc); 224183725Sjkoshy if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) 225183725Sjkoshy mii->mii_media_active = IFM_ETHER|IFM_HPNA_1; 226183725Sjkoshy 227183725Sjkoshy /* Callback if something changed. */ 228183725Sjkoshy mii_phy_update(sc, cmd); 229183725Sjkoshy return (0); 230183725Sjkoshy} 231183725Sjkoshy