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 */ 28 29 /* 30 * driver for RealTek RTL8150 internal PHY 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/socket.h> 38 #include <sys/bus.h> 39 40 #include <net/if.h> 41 #include <net/if_media.h> 42 43 #include <dev/netif/mii_layer/mii.h> 44 #include <dev/netif/mii_layer/miivar.h> 45 #include <dev/netif/mii_layer/ruephyreg.h> 46 47 #include "miibus_if.h" 48 49 static int ruephy_probe(device_t); 50 static int ruephy_attach(device_t); 51 52 static device_method_t ruephy_methods[] = { 53 /* device interface */ 54 DEVMETHOD(device_probe, ruephy_probe), 55 DEVMETHOD(device_attach, ruephy_attach), 56 DEVMETHOD(device_detach, ukphy_detach), 57 DEVMETHOD(device_shutdown, bus_generic_shutdown), 58 DEVMETHOD_END 59 }; 60 61 static devclass_t ruephy_devclass; 62 63 static driver_t ruephy_driver = { 64 "ruephy", 65 ruephy_methods, 66 sizeof(struct mii_softc) 67 }; 68 69 DRIVER_MODULE(ruephy, miibus, ruephy_driver, ruephy_devclass, NULL, NULL); 70 71 static int ruephy_service(struct mii_softc *, struct mii_data *, int); 72 static void ruephy_reset(struct mii_softc *); 73 static void ruephy_status(struct mii_softc *); 74 75 static int 76 ruephy_probe(device_t dev) 77 { 78 struct mii_attach_args *ma; 79 device_t parent; 80 81 ma = device_get_ivars(dev); 82 parent = device_get_parent(device_get_parent(dev)); 83 84 /* 85 * RealTek RTL8150 PHY doesn't have vendor/device ID registers: 86 * the rue driver fakes up a return value of all zeros. 87 */ 88 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 89 MII_MODEL(ma->mii_id2) != 0) 90 return (ENXIO); 91 92 /* 93 * Make sure the parent is an 'rue'. 94 */ 95 if (strcmp(device_get_name(parent), "rue") != 0) 96 return (ENXIO); 97 98 device_set_desc(dev, "RealTek RTL8150 internal media interface"); 99 100 return (0); 101 } 102 103 static int 104 ruephy_attach(device_t dev) 105 { 106 struct mii_softc *sc; 107 struct mii_attach_args *ma; 108 struct mii_data *mii; 109 110 sc = device_get_softc(dev); 111 ma = device_get_ivars(dev); 112 mii_softc_init(sc, ma); 113 sc->mii_dev = device_get_parent(dev); 114 mii = device_get_softc(sc->mii_dev); 115 116 /* 117 * The RealTek PHY can never be isolated, so never allow non-zero 118 * instances! 119 */ 120 if (mii->mii_instance != 0) { 121 device_printf(dev, "ignoring this PHY, non-zero instance\n"); 122 return (ENXIO); 123 } 124 125 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 126 127 sc->mii_inst = mii->mii_instance; 128 sc->mii_service = ruephy_service; 129 sc->mii_reset = ruephy_reset; 130 sc->mii_pdata = mii; 131 mii->mii_instance++; 132 133 sc->mii_flags |= MIIF_NOISOLATE; 134 135 ruephy_reset(sc); 136 137 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 138 139 device_printf(dev, " "); 140 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 141 kprintf("no media present"); 142 else 143 mii_phy_add_media(sc); 144 kprintf("\n"); 145 146 MIIBUS_MEDIAINIT(sc->mii_dev); 147 return (0); 148 } 149 150 static int 151 ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 152 { 153 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 154 int reg; 155 156 /* 157 * We can't isolate the RealTek RTL8150 PHY, 158 * so it has to be the only one! 159 */ 160 KASSERT(IFM_INST(ife->ifm_media) == sc->mii_inst, 161 ("ruephy_service: can't isolate RealTek RTL8150 PHY")); 162 163 switch (cmd) { 164 case MII_POLLSTAT: 165 break; 166 167 case MII_MEDIACHG: 168 /* 169 * If the interface is not up, don't do anything. 170 */ 171 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 172 break; 173 174 if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_T4) { 175 /* 176 * XXX Not supported as a manual setting right now. 177 */ 178 return (EINVAL); 179 } 180 181 mii_phy_set_media(sc); 182 break; 183 184 case MII_TICK: 185 /* 186 * Is the interface even up? 187 */ 188 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 189 return (0); 190 191 /* 192 * Only used for autonegotiation. 193 */ 194 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 195 break; 196 197 /* 198 * Check to see if we have link. If we do, we don't 199 * need to restart the autonegotiation process. Read 200 * the MSR twice in case it's latched. 201 */ 202 reg = PHY_READ(sc, RUEPHY_MII_MSR) | 203 PHY_READ(sc, RUEPHY_MII_MSR); 204 if (reg & RUEPHY_MSR_LINK) { 205 sc->mii_ticks = 0; 206 break; 207 } 208 209 /* 210 * Only retry autonegotiation every 5 seconds. 211 */ 212 if (++sc->mii_ticks != 5) 213 return (0); 214 215 sc->mii_ticks = 0; 216 ruephy_reset(sc); 217 218 if (mii_phy_auto(sc, 0) == EJUSTRETURN) 219 return (0); 220 break; 221 } 222 223 /* Update the media status. */ 224 ruephy_status(sc); 225 226 /* Callback if something changed. */ 227 mii_phy_update(sc, cmd); 228 return (0); 229 } 230 231 static void 232 ruephy_reset(struct mii_softc *sc) 233 { 234 235 mii_phy_reset(sc); 236 237 /* 238 * XXX RealTek RTL8150 PHY doesn't set the BMCR properly after 239 * XXX reset, which breaks autonegotiation. 240 */ 241 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN); 242 } 243 244 static void 245 ruephy_status(struct mii_softc *sc) 246 { 247 struct mii_data *mii = sc->mii_pdata; 248 int bmsr, bmcr, msr; 249 250 mii->mii_media_status = IFM_AVALID; 251 mii->mii_media_active = IFM_ETHER; 252 253 msr = PHY_READ(sc, RUEPHY_MII_MSR) | PHY_READ(sc, RUEPHY_MII_MSR); 254 if (msr & RUEPHY_MSR_LINK) 255 mii->mii_media_status |= IFM_ACTIVE; 256 257 bmcr = PHY_READ(sc, MII_BMCR); 258 if (bmcr & BMCR_ISO) { 259 mii->mii_media_active |= IFM_NONE; 260 mii->mii_media_status = 0; 261 return; 262 } 263 264 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 265 266 if (bmcr & BMCR_AUTOEN) { 267 if ((bmsr & BMSR_ACOMP) == 0) { 268 /* Erg, still trying, I guess... */ 269 mii->mii_media_active |= IFM_NONE; 270 return; 271 } 272 273 if (msr & RUEPHY_MSR_SPEED100) 274 mii->mii_media_active |= IFM_100_TX; 275 else 276 mii->mii_media_active |= IFM_10_T; 277 278 if (msr & RUEPHY_MSR_DUPLEX) 279 mii->mii_media_active |= IFM_FDX; 280 } else { 281 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media; 282 } 283 } 284