xlphy.c revision 50758
150120Swpaul/* $NetBSD: exphy.c,v 1.16 1999/04/23 04:24:32 thorpej Exp $ */ 250120Swpaul 350120Swpaul/*- 450120Swpaul * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 550120Swpaul * All rights reserved. 650120Swpaul * 750120Swpaul * This code is derived from software contributed to The NetBSD Foundation 850120Swpaul * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 950120Swpaul * NASA Ames Research Center, and by Frank van der Linden. 1050120Swpaul * 1150120Swpaul * Redistribution and use in source and binary forms, with or without 1250120Swpaul * modification, are permitted provided that the following conditions 1350120Swpaul * are met: 1450120Swpaul * 1. Redistributions of source code must retain the above copyright 1550120Swpaul * notice, this list of conditions and the following disclaimer. 1650120Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1750120Swpaul * notice, this list of conditions and the following disclaimer in the 1850120Swpaul * documentation and/or other materials provided with the distribution. 1950120Swpaul * 3. All advertising materials mentioning features or use of this software 2050120Swpaul * must display the following acknowledgement: 2150120Swpaul * This product includes software developed by the NetBSD 2250120Swpaul * Foundation, Inc. and its contributors. 2350120Swpaul * 4. Neither the name of The NetBSD Foundation nor the names of its 2450120Swpaul * contributors may be used to endorse or promote products derived 2550120Swpaul * from this software without specific prior written permission. 2650120Swpaul * 2750120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2850120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2950120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3050120Swpaul * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3150120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3250120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3350120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3450120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3550120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3650120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3750120Swpaul * POSSIBILITY OF SUCH DAMAGE. 3850120Swpaul */ 3950120Swpaul 4050120Swpaul/* 4150120Swpaul * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 4250120Swpaul * 4350120Swpaul * Redistribution and use in source and binary forms, with or without 4450120Swpaul * modification, are permitted provided that the following conditions 4550120Swpaul * are met: 4650120Swpaul * 1. Redistributions of source code must retain the above copyright 4750120Swpaul * notice, this list of conditions and the following disclaimer. 4850120Swpaul * 2. Redistributions in binary form must reproduce the above copyright 4950120Swpaul * notice, this list of conditions and the following disclaimer in the 5050120Swpaul * documentation and/or other materials provided with the distribution. 5150120Swpaul * 3. All advertising materials mentioning features or use of this software 5250120Swpaul * must display the following acknowledgement: 5350120Swpaul * This product includes software developed by Manuel Bouyer. 5450120Swpaul * 4. The name of the author may not be used to endorse or promote products 5550120Swpaul * derived from this software without specific prior written permission. 5650120Swpaul * 5750120Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 5850120Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5950120Swpaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 6050120Swpaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 6150120Swpaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 6250120Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6350120Swpaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6450120Swpaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6550120Swpaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 6650120Swpaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6750120Swpaul */ 6850120Swpaul 6950120Swpaul/* 7050120Swpaul * driver for 3Com internal PHYs 7150120Swpaul */ 7250120Swpaul 7350120Swpaul#include <sys/param.h> 7450120Swpaul#include <sys/systm.h> 7550120Swpaul#include <sys/kernel.h> 7650120Swpaul#include <sys/malloc.h> 7750120Swpaul#include <sys/socket.h> 7850120Swpaul#include <sys/module.h> 7950120Swpaul#include <sys/bus.h> 8050120Swpaul 8150120Swpaul#include <net/if.h> 8250120Swpaul#include <net/if_media.h> 8350120Swpaul 8450120Swpaul#include <dev/mii/mii.h> 8550120Swpaul#include <dev/mii/miivar.h> 8650120Swpaul#include <dev/mii/miidevs.h> 8750120Swpaul 8850120Swpaul#include "miibus_if.h" 8950120Swpaul 9050120Swpaul#if !defined(lint) 9150120Swpaulstatic const char rcsid[] = 9250758Swpaul "$FreeBSD: head/sys/dev/mii/exphy.c 50758 1999-09-01 17:07:27Z wpaul $"; 9350120Swpaul#endif 9450120Swpaul 9550120Swpaulstatic int exphy_probe __P((device_t)); 9650120Swpaulstatic int exphy_attach __P((device_t)); 9750120Swpaulstatic int exphy_detach __P((device_t)); 9850120Swpaul 9950120Swpaulstatic device_method_t exphy_methods[] = { 10050120Swpaul /* device interface */ 10150120Swpaul DEVMETHOD(device_probe, exphy_probe), 10250120Swpaul DEVMETHOD(device_attach, exphy_attach), 10350120Swpaul DEVMETHOD(device_detach, exphy_detach), 10450120Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 10550120Swpaul { 0, 0 } 10650120Swpaul}; 10750120Swpaul 10850120Swpaulstatic devclass_t exphy_devclass; 10950120Swpaul 11050120Swpaulstatic driver_t exphy_driver = { 11150120Swpaul "xlphy", 11250120Swpaul exphy_methods, 11350120Swpaul sizeof(struct mii_softc) 11450120Swpaul}; 11550120Swpaul 11650120SwpaulDRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0); 11750120Swpaul 11850120Swpaulint exphy_service __P((struct mii_softc *, struct mii_data *, int)); 11950120Swpaulvoid exphy_reset __P((struct mii_softc *)); 12050120Swpaul 12150120Swpaulstatic int exphy_probe(dev) 12250120Swpaul device_t dev; 12350120Swpaul{ 12450120Swpaul struct mii_attach_args *ma; 12550120Swpaul device_t parent; 12650120Swpaul 12750120Swpaul ma = device_get_ivars(dev); 12850120Swpaul parent = device_get_parent(device_get_parent(dev)); 12950120Swpaul 13050120Swpaul /* 13150120Swpaul * Argh, 3Com PHY reports oui == 0 model == 0! 13250120Swpaul */ 13350577Swpaul if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 13450577Swpaul MII_MODEL(ma->mii_id2) != 0) && 13550577Swpaul (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM || 13650577Swpaul MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3c905Cphy)) 13750120Swpaul return (ENXIO); 13850120Swpaul 13950120Swpaul /* 14050120Swpaul * Make sure the parent is an `ex'. 14150120Swpaul */ 14250120Swpaul if (strcmp(device_get_name(parent), "xl") != 0) 14350120Swpaul return (ENXIO); 14450120Swpaul 14550577Swpaul if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0) 14650577Swpaul device_set_desc(dev, "3Com internal media interface"); 14750577Swpaul else 14850577Swpaul device_set_desc(dev, MII_STR_BROADCOM_3c905Cphy); 14950120Swpaul 15050120Swpaul return (0); 15150120Swpaul} 15250120Swpaul 15350120Swpaulstatic int exphy_attach(dev) 15450120Swpaul device_t dev; 15550120Swpaul{ 15650120Swpaul struct mii_softc *sc; 15750120Swpaul struct mii_attach_args *ma; 15850120Swpaul struct mii_data *mii; 15950120Swpaul 16050120Swpaul sc = device_get_softc(dev); 16150120Swpaul ma = device_get_ivars(dev); 16250120Swpaul sc->mii_dev = device_get_parent(dev); 16350120Swpaul mii = device_get_softc(sc->mii_dev); 16450120Swpaul 16550120Swpaul /* 16650120Swpaul * The 3Com PHY can never be isolated, so never allow non-zero 16750120Swpaul * instances! 16850120Swpaul */ 16950120Swpaul if (mii->mii_instance != 0) { 17050120Swpaul device_printf(dev, "ignoring this PHY, non-zero instance\n"); 17150120Swpaul return(ENXIO); 17250120Swpaul } 17350120Swpaul 17450758Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 17550758Swpaul 17650758Swpaul sc->mii_inst = mii->mii_instance; 17750758Swpaul sc->mii_phy = ma->mii_phyno; 17850758Swpaul sc->mii_service = exphy_service; 17950758Swpaul sc->mii_pdata = mii; 18050120Swpaul mii->mii_instance++; 18150120Swpaul 18250120Swpaul sc->mii_flags |= MIIF_NOISOLATE; 18350120Swpaul 18450120Swpaul#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 18550120Swpaul 18650120Swpaul#if 0 /* See above. */ 18750120Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 18850120Swpaul BMCR_ISO); 18950120Swpaul#endif 19050120Swpaul 19150120Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 19250120Swpaul BMCR_LOOP|BMCR_S100); 19350120Swpaul 19450120Swpaul exphy_reset(sc); 19550120Swpaul 19650120Swpaul sc->mii_capabilities = 19750120Swpaul PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 19850120Swpaul device_printf(dev, " "); 19950120Swpaul if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 20050120Swpaul printf("no media present"); 20150120Swpaul else 20250120Swpaul mii_add_media(mii, sc->mii_capabilities, 20350120Swpaul sc->mii_inst); 20450120Swpaul printf("\n"); 20550120Swpaul#undef ADD 20650120Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 20750120Swpaul return(0); 20850120Swpaul} 20950120Swpaul 21050120Swpaulstatic int exphy_detach(dev) 21150120Swpaul device_t dev; 21250120Swpaul{ 21350120Swpaul struct mii_softc *sc; 21450120Swpaul struct mii_data *mii; 21550120Swpaul 21650120Swpaul sc = device_get_softc(dev); 21750120Swpaul mii = device_get_softc(device_get_parent(dev)); 21850120Swpaul sc->mii_dev = NULL; 21950120Swpaul LIST_REMOVE(sc, mii_list); 22050120Swpaul 22150120Swpaul return(0); 22250120Swpaul} 22350120Swpaul 22450120Swpaulint 22550120Swpaulexphy_service(sc, mii, cmd) 22650120Swpaul struct mii_softc *sc; 22750120Swpaul struct mii_data *mii; 22850120Swpaul int cmd; 22950120Swpaul{ 23050120Swpaul struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 23150120Swpaul 23250120Swpaul /* 23350120Swpaul * We can't isolate the 3Com PHY, so it has to be the only one! 23450120Swpaul */ 23550120Swpaul if (IFM_INST(ife->ifm_media) != sc->mii_inst) 23650120Swpaul panic("exphy_service: can't isolate 3Com PHY"); 23750120Swpaul 23850120Swpaul switch (cmd) { 23950120Swpaul case MII_POLLSTAT: 24050120Swpaul break; 24150120Swpaul 24250120Swpaul case MII_MEDIACHG: 24350120Swpaul /* 24450120Swpaul * If the interface is not up, don't do anything. 24550120Swpaul */ 24650120Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 24750120Swpaul break; 24850120Swpaul 24950120Swpaul switch (IFM_SUBTYPE(ife->ifm_media)) { 25050120Swpaul case IFM_AUTO: 25150120Swpaul /* 25250120Swpaul * If we're already in auto mode, just return. 25350120Swpaul */ 25450120Swpaul if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) 25550120Swpaul return (0); 25650120Swpaul (void) mii_phy_auto(sc, 1); 25750120Swpaul break; 25850120Swpaul case IFM_100_T4: 25950120Swpaul /* 26050120Swpaul * XXX Not supported as a manual setting right now. 26150120Swpaul */ 26250120Swpaul return (EINVAL); 26350120Swpaul default: 26450120Swpaul /* 26550120Swpaul * BMCR data is stored in the ifmedia entry. 26650120Swpaul */ 26750120Swpaul PHY_WRITE(sc, MII_ANAR, 26850120Swpaul mii_anar(ife->ifm_media)); 26950120Swpaul PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 27050120Swpaul } 27150120Swpaul break; 27250120Swpaul 27350120Swpaul case MII_TICK: 27450120Swpaul /* 27550120Swpaul * Only used for autonegotiation. 27650120Swpaul */ 27750120Swpaul if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 27850120Swpaul return (0); 27950120Swpaul 28050120Swpaul /* 28150120Swpaul * Is the interface even up? 28250120Swpaul */ 28350120Swpaul if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 28450120Swpaul return (0); 28550120Swpaul 28650120Swpaul /* 28750120Swpaul * The 3Com PHY's autonegotiation doesn't need to be 28850120Swpaul * kicked; it continues in the background. 28950120Swpaul */ 29050120Swpaul break; 29150120Swpaul } 29250120Swpaul 29350120Swpaul /* Update the media status. */ 29450120Swpaul ukphy_status(sc); 29550120Swpaul 29650120Swpaul /* Callback if something changed. */ 29750120Swpaul if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { 29850120Swpaul MIIBUS_STATCHG(sc->mii_dev); 29950120Swpaul sc->mii_active = mii->mii_media_active; 30050120Swpaul } 30150120Swpaul return (0); 30250120Swpaul} 30350120Swpaul 30450120Swpaulvoid 30550120Swpaulexphy_reset(sc) 30650120Swpaul struct mii_softc *sc; 30750120Swpaul{ 30850120Swpaul 30950120Swpaul mii_phy_reset(sc); 31050120Swpaul 31150120Swpaul /* 31250120Swpaul * XXX 3Com PHY doesn't set the BMCR properly after 31350120Swpaul * XXX reset, which breaks autonegotiation. 31450120Swpaul */ 31550120Swpaul PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX); 31650120Swpaul} 317