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.4 2005/11/05 10:01:54 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 static int ruephy_detach(device_t); 53 54 static device_method_t ruephy_methods[] = { 55 /* device interface */ 56 DEVMETHOD(device_probe, ruephy_probe), 57 DEVMETHOD(device_attach, ruephy_attach), 58 DEVMETHOD(device_detach, ruephy_detach), 59 DEVMETHOD(device_shutdown, bus_generic_shutdown), 60 { 0, 0 } 61 }; 62 63 static devclass_t ruephy_devclass; 64 65 static driver_t ruephy_driver = { 66 "ruephy", 67 ruephy_methods, 68 sizeof(struct mii_softc) 69 }; 70 71 DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, 0, 0); 72 73 static int ruephy_service(struct mii_softc *, struct mii_data *, int); 74 static void ruephy_reset(struct mii_softc *); 75 static void ruephy_status(struct mii_softc *); 76 77 static int 78 ruephy_probe(device_t dev) 79 { 80 struct mii_attach_args *ma; 81 device_t parent; 82 83 ma = device_get_ivars(dev); 84 parent = device_get_parent(device_get_parent(dev)); 85 86 /* 87 * RealTek RTL8150 PHY doesn't have vendor/device ID registers: 88 * the rue driver fakes up a return value of all zeros. 89 */ 90 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 91 MII_MODEL(ma->mii_id2) != 0) 92 return (ENXIO); 93 94 /* 95 * Make sure the parent is an 'rue'. 96 */ 97 if (strcmp(device_get_name(parent), "rue") != 0) 98 return (ENXIO); 99 100 device_set_desc(dev, "RealTek RTL8150 internal media interface"); 101 102 return (0); 103 } 104 105 static int 106 ruephy_attach(device_t dev) 107 { 108 struct mii_softc *sc; 109 struct mii_attach_args *ma; 110 struct mii_data *mii; 111 112 sc = device_get_softc(dev); 113 ma = device_get_ivars(dev); 114 mii_softc_init(sc, ma); 115 sc->mii_dev = device_get_parent(dev); 116 mii = device_get_softc(sc->mii_dev); 117 118 /* 119 * The RealTek PHY can never be isolated, so never allow non-zero 120 * instances! 121 */ 122 if (mii->mii_instance != 0) { 123 device_printf(dev, "ignoring this PHY, non-zero instance\n"); 124 return (ENXIO); 125 } 126 127 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 128 129 sc->mii_inst = mii->mii_instance; 130 sc->mii_service = ruephy_service; 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 = 139 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 140 device_printf(dev, " "); 141 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 142 printf("no media present"); 143 else 144 mii_add_media(sc, sc->mii_capabilities); 145 printf("\n"); 146 147 MIIBUS_MEDIAINIT(sc->mii_dev); 148 return (0); 149 } 150 151 static int 152 ruephy_detach(device_t dev) 153 { 154 struct mii_softc *sc; 155 struct mii_data *mii; 156 157 sc = device_get_softc(dev); 158 mii = device_get_softc(device_get_softc(dev)); 159 mii_phy_auto_stop(sc); 160 sc->mii_dev = NULL; 161 LIST_REMOVE(sc, mii_list); 162 163 return (0); 164 } 165 166 static int 167 ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 168 { 169 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 170 int reg; 171 172 /* 173 * We can't isolate the RealTek RTL8150 PHY, 174 * so it has to be the only one! 175 */ 176 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 177 panic("ruephy_service: can't isolate RealTek RTL8150 PHY"); 178 179 switch (cmd) { 180 case MII_POLLSTAT: 181 break; 182 183 case MII_MEDIACHG: 184 /* 185 * If the interface is not up, don't do anything. 186 */ 187 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 188 break; 189 190 switch (IFM_SUBTYPE(ife->ifm_media)) { 191 case IFM_AUTO: 192 /* 193 * If we're already in auto mode, just return. 194 */ 195 if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) 196 return (0); 197 (void) mii_phy_auto(sc, 1); 198 break; 199 case IFM_100_T4: 200 /* 201 * XXX Not supported as a manual setting right now. 202 */ 203 return (EINVAL); 204 default: 205 /* 206 * BMCR data is stored in the ifmedia entry. 207 */ 208 PHY_WRITE(sc, MII_ANAR, 209 mii_anar(ife->ifm_media)); 210 PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 211 } 212 break; 213 214 case MII_TICK: 215 /* 216 * Is the interface even up? 217 */ 218 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 219 return (0); 220 221 /* 222 * Only used for autonegotiation. 223 */ 224 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 225 break; 226 227 /* 228 * Check to see if we have link. If we do, we don't 229 * need to restart the autonegotiation process. Read 230 * the MSR twice in case it's latched. 231 */ 232 reg = PHY_READ(sc, RUEPHY_MII_MSR) | 233 PHY_READ(sc, RUEPHY_MII_MSR); 234 if (reg & RUEPHY_MSR_LINK) 235 break; 236 237 /* 238 * Only retry autonegotiation every 5 seconds. 239 */ 240 if (++sc->mii_ticks != 5) 241 return (0); 242 243 sc->mii_ticks = 0; 244 ruephy_reset(sc); 245 if (mii_phy_auto(sc, 0) == EJUSTRETURN) 246 return (0); 247 break; 248 } 249 250 /* Update the media status. */ 251 ruephy_status(sc); 252 253 /* Callback if something changed. */ 254 if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { 255 MIIBUS_STATCHG(sc->mii_dev); 256 sc->mii_active = mii->mii_media_active; 257 } 258 259 return (0); 260 } 261 262 static void 263 ruephy_reset(struct mii_softc *sc) 264 { 265 266 mii_phy_reset(sc); 267 268 /* 269 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 270 * XXX reset, which breaks autonegotiation. 271 */ 272 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN); 273 } 274 275 static void 276 ruephy_status(struct mii_softc *phy) 277 { 278 struct mii_data *mii = phy->mii_pdata; 279 int bmsr, bmcr, msr; 280 281 mii->mii_media_status = IFM_AVALID; 282 mii->mii_media_active = IFM_ETHER; 283 284 msr = PHY_READ(phy, RUEPHY_MII_MSR) | PHY_READ(phy, RUEPHY_MII_MSR); 285 if (msr & RUEPHY_MSR_LINK) 286 mii->mii_media_status |= IFM_ACTIVE; 287 288 bmcr = PHY_READ(phy, MII_BMCR); 289 if (bmcr & BMCR_ISO) { 290 mii->mii_media_active |= IFM_NONE; 291 mii->mii_media_status = 0; 292 return; 293 } 294 295 bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); 296 297 if (bmcr & BMCR_AUTOEN) { 298 if ((bmsr & BMSR_ACOMP) == 0) { 299 /* Erg, still trying, I guess... */ 300 mii->mii_media_active |= IFM_NONE; 301 return; 302 } 303 304 if (msr & RUEPHY_MSR_SPEED100) 305 mii->mii_media_active |= IFM_100_TX; 306 else 307 mii->mii_media_active |= IFM_10_T; 308 309 if (msr & RUEPHY_MSR_DUPLEX) 310 mii->mii_media_active |= IFM_FDX; 311 } else 312 mii->mii_media_active = mii_media_from_bmcr(bmcr); 313 } 314