1 /*- 2 * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/dev/mii/ruephy.c,v 1.1.4.1 2003/07/30 13:57:35 akiyama Exp $ 27 * $DragonFly: src/sys/dev/netif/mii_layer/ruephy.c,v 1.7 2008/07/22 10:59:16 sephe Exp $ 28 */ 29 30 /* 31 * driver for RealTek RTL8150 internal PHY 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/socket.h> 39 #include <sys/bus.h> 40 41 #include <net/if.h> 42 #include <net/if_media.h> 43 44 #include <dev/netif/mii_layer/mii.h> 45 #include <dev/netif/mii_layer/miivar.h> 46 #include <dev/netif/mii_layer/ruephyreg.h> 47 48 #include "miibus_if.h" 49 50 static int ruephy_probe(device_t); 51 static int ruephy_attach(device_t); 52 53 static device_method_t ruephy_methods[] = { 54 /* device interface */ 55 DEVMETHOD(device_probe, ruephy_probe), 56 DEVMETHOD(device_attach, ruephy_attach), 57 DEVMETHOD(device_detach, ukphy_detach), 58 DEVMETHOD(device_shutdown, bus_generic_shutdown), 59 { 0, 0 } 60 }; 61 62 static devclass_t ruephy_devclass; 63 64 static driver_t ruephy_driver = { 65 "ruephy", 66 ruephy_methods, 67 sizeof(struct mii_softc) 68 }; 69 70 DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); 71 72 static int ruephy_service(struct mii_softc *, struct mii_data *, int); 73 static void ruephy_reset(struct mii_softc *); 74 static void ruephy_status(struct mii_softc *); 75 76 static int 77 ruephy_probe(device_t dev) 78 { 79 struct mii_attach_args *ma; 80 device_t parent; 81 82 ma = device_get_ivars(dev); 83 parent = device_get_parent(device_get_parent(dev)); 84 85 /* 86 * RealTek RTL8150 PHY doesn't have vendor/device ID registers: 87 * the rue driver fakes up a return value of all zeros. 88 */ 89 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 90 MII_MODEL(ma->mii_id2) != 0) 91 return (ENXIO); 92 93 /* 94 * Make sure the parent is an 'rue'. 95 */ 96 if (strcmp(device_get_name(parent), "rue") != 0) 97 return (ENXIO); 98 99 device_set_desc(dev, "RealTek RTL8150 internal media interface"); 100 101 return (0); 102 } 103 104 static int 105 ruephy_attach(device_t dev) 106 { 107 struct mii_softc *sc; 108 struct mii_attach_args *ma; 109 struct mii_data *mii; 110 111 sc = device_get_softc(dev); 112 ma = device_get_ivars(dev); 113 mii_softc_init(sc, ma); 114 sc->mii_dev = device_get_parent(dev); 115 mii = device_get_softc(sc->mii_dev); 116 117 /* 118 * The RealTek PHY can never be isolated, so never allow non-zero 119 * instances! 120 */ 121 if (mii->mii_instance != 0) { 122 device_printf(dev, "ignoring this PHY, non-zero instance\n"); 123 return (ENXIO); 124 } 125 126 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 127 128 sc->mii_inst = mii->mii_instance; 129 sc->mii_service = ruephy_service; 130 sc->mii_reset = ruephy_reset; 131 sc->mii_pdata = mii; 132 mii->mii_instance++; 133 134 sc->mii_flags |= MIIF_NOISOLATE; 135 136 ruephy_reset(sc); 137 138 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 139 140 device_printf(dev, " "); 141 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 142 kprintf("no media present"); 143 else 144 mii_phy_add_media(sc); 145 kprintf("\n"); 146 147 MIIBUS_MEDIAINIT(sc->mii_dev); 148 return (0); 149 } 150 151 static int 152 ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 153 { 154 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 155 int reg; 156 157 /* 158 * We can't isolate the RealTek RTL8150 PHY, 159 * so it has to be the only one! 160 */ 161 KASSERT(IFM_INST(ife->ifm_media) == sc->mii_inst, 162 ("ruephy_service: can't isolate RealTek RTL8150 PHY")); 163 164 switch (cmd) { 165 case MII_POLLSTAT: 166 break; 167 168 case MII_MEDIACHG: 169 /* 170 * If the interface is not up, don't do anything. 171 */ 172 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 173 break; 174 175 if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_T4) { 176 /* 177 * XXX Not supported as a manual setting right now. 178 */ 179 return (EINVAL); 180 } 181 182 mii_phy_set_media(sc); 183 break; 184 185 case MII_TICK: 186 /* 187 * Is the interface even up? 188 */ 189 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 190 return (0); 191 192 /* 193 * Only used for autonegotiation. 194 */ 195 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 196 break; 197 198 /* 199 * Check to see if we have link. If we do, we don't 200 * need to restart the autonegotiation process. Read 201 * the MSR twice in case it's latched. 202 */ 203 reg = PHY_READ(sc, RUEPHY_MII_MSR) | 204 PHY_READ(sc, RUEPHY_MII_MSR); 205 if (reg & RUEPHY_MSR_LINK) { 206 sc->mii_ticks = 0; 207 break; 208 } 209 210 /* 211 * Only retry autonegotiation every 5 seconds. 212 */ 213 if (++sc->mii_ticks != 5) 214 return (0); 215 216 sc->mii_ticks = 0; 217 ruephy_reset(sc); 218 219 if (mii_phy_auto(sc, 0) == EJUSTRETURN) 220 return (0); 221 break; 222 } 223 224 /* Update the media status. */ 225 ruephy_status(sc); 226 227 /* Callback if something changed. */ 228 mii_phy_update(sc, cmd); 229 return (0); 230 } 231 232 static void 233 ruephy_reset(struct mii_softc *sc) 234 { 235 236 mii_phy_reset(sc); 237 238 /* 239 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 240 * XXX reset, which breaks autonegotiation. 241 */ 242 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN); 243 } 244 245 static void 246 ruephy_status(struct mii_softc *sc) 247 { 248 struct mii_data *mii = sc->mii_pdata; 249 int bmsr, bmcr, msr; 250 251 mii->mii_media_status = IFM_AVALID; 252 mii->mii_media_active = IFM_ETHER; 253 254 msr = PHY_READ(sc, RUEPHY_MII_MSR) | PHY_READ(sc, RUEPHY_MII_MSR); 255 if (msr & RUEPHY_MSR_LINK) 256 mii->mii_media_status |= IFM_ACTIVE; 257 258 bmcr = PHY_READ(sc, MII_BMCR); 259 if (bmcr & BMCR_ISO) { 260 mii->mii_media_active |= IFM_NONE; 261 mii->mii_media_status = 0; 262 return; 263 } 264 265 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 266 267 if (bmcr & BMCR_AUTOEN) { 268 if ((bmsr & BMSR_ACOMP) == 0) { 269 /* Erg, still trying, I guess... */ 270 mii->mii_media_active |= IFM_NONE; 271 return; 272 } 273 274 if (msr & RUEPHY_MSR_SPEED100) 275 mii->mii_media_active |= IFM_100_TX; 276 else 277 mii->mii_media_active |= IFM_10_T; 278 279 if (msr & RUEPHY_MSR_DUPLEX) 280 mii->mii_media_active |= IFM_FDX; 281 } else { 282 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; 283 } 284 } 285