xlphy.c revision 92739
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/socket.h> 7750120Swpaul#include <sys/module.h> 7850120Swpaul#include <sys/bus.h> 7950120Swpaul 8050120Swpaul#include <net/if.h> 8150120Swpaul#include <net/if_media.h> 8250120Swpaul 8350120Swpaul#include <dev/mii/mii.h> 8450120Swpaul#include <dev/mii/miivar.h> 8550120Swpaul#include <dev/mii/miidevs.h> 8650120Swpaul 8750120Swpaul#include "miibus_if.h" 8850120Swpaul 8950120Swpaul#if !defined(lint) 9050120Swpaulstatic const char rcsid[] = 9150758Swpaul "$FreeBSD: head/sys/dev/mii/exphy.c 92739 2002-03-20 02:08:01Z alfred $"; 9250120Swpaul#endif 9350120Swpaul 9492739Salfredstatic int exphy_probe (device_t); 9592739Salfredstatic int exphy_attach (device_t); 9692739Salfredstatic int exphy_detach (device_t); 9750120Swpaul 9850120Swpaulstatic device_method_t exphy_methods[] = { 9950120Swpaul /* device interface */ 10050120Swpaul DEVMETHOD(device_probe, exphy_probe), 10150120Swpaul DEVMETHOD(device_attach, exphy_attach), 10250120Swpaul DEVMETHOD(device_detach, exphy_detach), 10350120Swpaul DEVMETHOD(device_shutdown, bus_generic_shutdown), 10450120Swpaul { 0, 0 } 10550120Swpaul}; 10650120Swpaul 10750120Swpaulstatic devclass_t exphy_devclass; 10850120Swpaul 10950120Swpaulstatic driver_t exphy_driver = { 11050120Swpaul "xlphy", 11150120Swpaul exphy_methods, 11250120Swpaul sizeof(struct mii_softc) 11350120Swpaul}; 11450120Swpaul 11550120SwpaulDRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0); 11650120Swpaul 11792739Salfredstatic int exphy_service(struct mii_softc *, struct mii_data *, int); 11892739Salfredstatic void exphy_reset(struct mii_softc *); 11950120Swpaul 12050120Swpaulstatic int exphy_probe(dev) 12150120Swpaul device_t dev; 12250120Swpaul{ 12350120Swpaul struct mii_attach_args *ma; 12450120Swpaul device_t parent; 12550120Swpaul 12650120Swpaul ma = device_get_ivars(dev); 12750120Swpaul parent = device_get_parent(device_get_parent(dev)); 12850120Swpaul 12950120Swpaul /* 13050120Swpaul * Argh, 3Com PHY reports oui == 0 model == 0! 13150120Swpaul */ 13250577Swpaul if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 13350577Swpaul MII_MODEL(ma->mii_id2) != 0) && 13450577Swpaul (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM || 13550577Swpaul MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3c905Cphy)) 13650120Swpaul return (ENXIO); 13750120Swpaul 13850120Swpaul /* 13950120Swpaul * Make sure the parent is an `ex'. 14050120Swpaul */ 14150120Swpaul if (strcmp(device_get_name(parent), "xl") != 0) 14250120Swpaul return (ENXIO); 14350120Swpaul 14450577Swpaul if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0) 14550577Swpaul device_set_desc(dev, "3Com internal media interface"); 14650577Swpaul else 14750577Swpaul device_set_desc(dev, MII_STR_BROADCOM_3c905Cphy); 14850120Swpaul 14950120Swpaul return (0); 15050120Swpaul} 15150120Swpaul 15250120Swpaulstatic int exphy_attach(dev) 15350120Swpaul device_t dev; 15450120Swpaul{ 15550120Swpaul struct mii_softc *sc; 15650120Swpaul struct mii_attach_args *ma; 15750120Swpaul struct mii_data *mii; 15850120Swpaul 15950120Swpaul sc = device_get_softc(dev); 16050120Swpaul ma = device_get_ivars(dev); 16150120Swpaul sc->mii_dev = device_get_parent(dev); 16250120Swpaul mii = device_get_softc(sc->mii_dev); 16350120Swpaul 16450120Swpaul /* 16550120Swpaul * The 3Com PHY can never be isolated, so never allow non-zero 16650120Swpaul * instances! 16750120Swpaul */ 16850120Swpaul if (mii->mii_instance != 0) { 16950120Swpaul device_printf(dev, "ignoring this PHY, non-zero instance\n"); 17050120Swpaul return(ENXIO); 17150120Swpaul } 17250120Swpaul 17350758Swpaul LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 17450758Swpaul 17550758Swpaul sc->mii_inst = mii->mii_instance; 17650758Swpaul sc->mii_phy = ma->mii_phyno; 17750758Swpaul sc->mii_service = exphy_service; 17850758Swpaul sc->mii_pdata = mii; 17950120Swpaul mii->mii_instance++; 18050120Swpaul 18150120Swpaul sc->mii_flags |= MIIF_NOISOLATE; 18250120Swpaul 18350120Swpaul#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 18450120Swpaul 18550120Swpaul#if 0 /* See above. */ 18650120Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 18750120Swpaul BMCR_ISO); 18850120Swpaul#endif 18950120Swpaul 19050120Swpaul ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 19150120Swpaul BMCR_LOOP|BMCR_S100); 19250120Swpaul 19350120Swpaul exphy_reset(sc); 19450120Swpaul 19550120Swpaul sc->mii_capabilities = 19650120Swpaul PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 19750120Swpaul device_printf(dev, " "); 19850120Swpaul if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 19950120Swpaul printf("no media present"); 20050120Swpaul else 20150120Swpaul mii_add_media(mii, sc->mii_capabilities, 20250120Swpaul sc->mii_inst); 20350120Swpaul printf("\n"); 20450120Swpaul#undef ADD 20550120Swpaul MIIBUS_MEDIAINIT(sc->mii_dev); 20650120Swpaul return(0); 20750120Swpaul} 20850120Swpaul 20950120Swpaulstatic int exphy_detach(dev) 21050120Swpaul device_t dev; 21150120Swpaul{ 21250120Swpaul struct mii_softc *sc; 21350120Swpaul struct mii_data *mii; 21450120Swpaul 21550120Swpaul sc = device_get_softc(dev); 21650120Swpaul mii = device_get_softc(device_get_parent(dev)); 21769925Swpaul mii_phy_auto_stop(sc); 21850120Swpaul sc->mii_dev = NULL; 21950120Swpaul LIST_REMOVE(sc, mii_list); 22050120Swpaul 22150120Swpaul return(0); 22250120Swpaul} 22350120Swpaul 22484145Sjlemonstatic int 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 /* 27584145Sjlemon * Is the interface even up? 27650120Swpaul */ 27784145Sjlemon if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 27850120Swpaul return (0); 27950120Swpaul 28050120Swpaul /* 28184145Sjlemon * Only used for autonegotiation. 28250120Swpaul */ 28384145Sjlemon if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 28484145Sjlemon break; 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. */ 29784145Sjlemon mii_phy_update(sc, cmd); 29850120Swpaul return (0); 29950120Swpaul} 30050120Swpaul 30184145Sjlemonstatic void 30250120Swpaulexphy_reset(sc) 30350120Swpaul struct mii_softc *sc; 30450120Swpaul{ 30550120Swpaul 30650120Swpaul mii_phy_reset(sc); 30750120Swpaul 30850120Swpaul /* 30950120Swpaul * XXX 3Com PHY doesn't set the BMCR properly after 31050120Swpaul * XXX reset, which breaks autonegotiation. 31150120Swpaul */ 31250120Swpaul PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX); 31350120Swpaul} 314