1 /* $OpenBSD: rlphy.c,v 1.30 2008/09/11 18:26:58 brad Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 1999 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Driver for the internal PHY found on RTL8139 based nics, based 31 * on drivers for the 'exphy' (Internal 3Com phys) and 'nsphy' 32 * (National Semiconductor DP83840). 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/socket.h> 40 #include <sys/errno.h> 41 42 #include <machine/bus.h> 43 44 #include <net/if.h> 45 #include <net/if_media.h> 46 47 #include <netinet/in.h> 48 #include <netinet/if_ether.h> 49 50 #include <dev/mii/mii.h> 51 #include <dev/mii/miivar.h> 52 #include <dev/mii/miidevs.h> 53 54 #include <dev/ic/rtl81x9reg.h> 55 56 int rlphymatch(struct device *, void *, void *); 57 void rlphyattach(struct device *, struct device *, void *); 58 59 struct cfattach rlphy_ca = { 60 sizeof(struct mii_softc), rlphymatch, rlphyattach, mii_phy_detach, 61 mii_phy_activate 62 }; 63 64 struct cfdriver rlphy_cd = { 65 NULL, "rlphy", DV_DULL 66 }; 67 68 int rlphy_service(struct mii_softc *, struct mii_data *, int); 69 void rlphy_status(struct mii_softc *); 70 71 const struct mii_phy_funcs rlphy_funcs = { 72 rlphy_service, rlphy_status, mii_phy_reset, 73 }; 74 75 static const struct mii_phydesc rlphys[] = { 76 { MII_OUI_REALTEK, MII_MODEL_REALTEK_RTL8201L, 77 MII_STR_REALTEK_RTL8201L }, 78 { MII_OUI_ICPLUS, MII_MODEL_ICPLUS_IP101, 79 MII_STR_ICPLUS_IP101 }, 80 81 { 0, 0, 82 NULL }, 83 }; 84 int 85 rlphymatch(struct device *parent, void *match, void *aux) 86 { 87 struct mii_attach_args *ma = aux; 88 char *devname; 89 90 devname = parent->dv_cfdata->cf_driver->cd_name; 91 92 if (mii_phy_match(ma, rlphys) != NULL) 93 return (10); 94 95 if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 || 96 MII_MODEL(ma->mii_id2) != 0) 97 return (0); 98 99 if ((strcmp(devname, "re") != 0) && 100 (strcmp(devname, "rl") != 0)) 101 return (0); 102 103 /* 104 * A "real" phy should get preference, but on the 8139 there 105 * is no phyid register. 106 */ 107 return (5); 108 } 109 110 void 111 rlphyattach(struct device *parent, struct device *self, void *aux) 112 { 113 struct mii_softc *sc = (struct mii_softc *)self; 114 struct mii_attach_args *ma = aux; 115 struct mii_data *mii = ma->mii_data; 116 const struct mii_phydesc *mpd; 117 118 mpd = mii_phy_match(ma, rlphys); 119 if (mpd != NULL) { 120 printf(": %s, rev. %d\n", mpd->mpd_name, 121 MII_REV(ma->mii_id2)); 122 } else 123 printf(": RTL internal PHY\n"); 124 125 sc->mii_inst = mii->mii_instance; 126 sc->mii_phy = ma->mii_phyno; 127 sc->mii_funcs = &rlphy_funcs; 128 sc->mii_pdata = mii; 129 sc->mii_flags = ma->mii_flags; 130 131 sc->mii_flags |= MIIF_NOISOLATE; 132 133 PHY_RESET(sc); 134 135 sc->mii_capabilities = 136 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 137 if (sc->mii_capabilities & BMSR_MEDIAMASK) 138 mii_phy_add_media(sc); 139 } 140 141 int 142 rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 143 { 144 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 145 146 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 147 return (ENXIO); 148 149 /* 150 * Can't isolate the RTL8139 phy, so it has to be the only one. 151 */ 152 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 153 panic("rlphy_service: attempt to isolate phy"); 154 155 switch (cmd) { 156 case MII_POLLSTAT: 157 break; 158 159 case MII_MEDIACHG: 160 /* 161 * If the interface is not up, don't do anything. 162 */ 163 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 164 break; 165 166 switch (IFM_SUBTYPE(ife->ifm_media)) { 167 case IFM_AUTO: 168 /* 169 * If we're already in auto mode, just return. 170 */ 171 if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) 172 return (0); 173 (void) mii_phy_auto(sc, 0); 174 break; 175 case IFM_100_T4: 176 /* 177 * XXX Not supported as a manual setting right now. 178 */ 179 return (EINVAL); 180 default: 181 /* 182 * BMCR data is stored in the ifmedia entry. 183 */ 184 PHY_WRITE(sc, MII_ANAR, 185 mii_anar(ife->ifm_media)); 186 PHY_WRITE(sc, MII_BMCR, ife->ifm_data); 187 } 188 break; 189 190 case MII_TICK: 191 /* 192 * Is the interface even up? 193 */ 194 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 195 return (0); 196 197 /* 198 * The RealTek PHY's autonegotiation doesn't need to be 199 * kicked; it continues in the background. 200 */ 201 break; 202 203 case MII_DOWN: 204 mii_phy_down(sc); 205 return (0); 206 } 207 208 /* Update the media status. */ 209 mii_phy_status(sc); 210 211 /* Callback if something changed. */ 212 mii_phy_update(sc, cmd); 213 return (0); 214 } 215 216 void 217 rlphy_status(struct mii_softc *sc) 218 { 219 struct mii_data *mii = sc->mii_pdata; 220 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 221 int bmsr, bmcr, anlpar; 222 char *devname; 223 224 devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; 225 226 mii->mii_media_status = IFM_AVALID; 227 mii->mii_media_active = IFM_ETHER; 228 229 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 230 if (bmsr & BMSR_LINK) 231 mii->mii_media_status |= IFM_ACTIVE; 232 233 bmcr = PHY_READ(sc, MII_BMCR); 234 if (bmcr & BMCR_ISO) { 235 mii->mii_media_active |= IFM_NONE; 236 mii->mii_media_status = 0; 237 return; 238 } 239 240 if (bmcr & BMCR_LOOP) 241 mii->mii_media_active |= IFM_LOOP; 242 243 if (bmcr & BMCR_AUTOEN) { 244 /* 245 * NWay autonegotiation takes the highest-order common 246 * bit of the ANAR and ANLPAR (i.e. best media advertised 247 * both by us and our link partner). 248 */ 249 if ((bmsr & BMSR_ACOMP) == 0) { 250 /* Erg, still trying, I guess... */ 251 mii->mii_media_active |= IFM_NONE; 252 return; 253 } 254 255 if ((anlpar = PHY_READ(sc, MII_ANAR) & 256 PHY_READ(sc, MII_ANLPAR))) { 257 if (anlpar & ANLPAR_TX_FD) 258 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 259 else if (anlpar & ANLPAR_T4) 260 mii->mii_media_active |= IFM_100_T4|IFM_HDX; 261 else if (anlpar & ANLPAR_TX) 262 mii->mii_media_active |= IFM_100_TX|IFM_HDX; 263 else if (anlpar & ANLPAR_10_FD) 264 mii->mii_media_active |= IFM_10_T|IFM_FDX; 265 else if (anlpar & ANLPAR_10) 266 mii->mii_media_active |= IFM_10_T|IFM_HDX; 267 else 268 mii->mii_media_active |= IFM_NONE; 269 return; 270 } 271 272 /* 273 * If the other side doesn't support NWAY, then the 274 * best we can do is determine if we have a 10Mbps or 275 * 100Mbps link. There's no way to know if the link 276 * is full or half duplex, so we default to half duplex 277 * and hope that the user is clever enough to manually 278 * change the media settings if we're wrong. 279 */ 280 281 /* 282 * The RealTek PHY supports non-NWAY link speed 283 * detection, however it does not report the link 284 * detection results via the ANLPAR or BMSR registers. 285 * (What? RealTek doesn't do things the way everyone 286 * else does? I'm just shocked, shocked I tell you.) 287 * To determine the link speed, we have to do one 288 * of two things: 289 * 290 * - If this is a standalone RealTek RTL8201(L) PHY, 291 * we can determine the link speed by testing bit 0 292 * in the magic, vendor-specific register at offset 293 * 0x19. 294 * 295 * - If this is a RealTek MAC with integrated PHY, we 296 * can test the 'SPEED10' bit of the MAC's media status 297 * register. 298 */ 299 if (strcmp("rl", devname) == 0 || 300 strcmp("re", devname) == 0) { 301 if (PHY_READ(sc, RL_MEDIASTAT) & RL_MEDIASTAT_SPEED10) 302 mii->mii_media_active |= IFM_10_T; 303 else 304 mii->mii_media_active |= IFM_100_TX; 305 } else { 306 if (PHY_READ(sc, 0x0019) & 0x01) 307 mii->mii_media_active |= IFM_100_TX; 308 else 309 mii->mii_media_active |= IFM_10_T; 310 } 311 mii->mii_media_active |= IFM_HDX; 312 } else 313 mii->mii_media_active = ife->ifm_media; 314 } 315