1 /* 2 * Copyright (c) 1997, 1998, 1999 3 * Bill Paul <wpaul@ee.columbia.edu>. 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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * $FreeBSD$ 33 */ 34 35 /* 36 * Pseudo-driver for internal NWAY support on DEC 21143 and workalike 37 * controllers. Technically we're abusing the miibus code to handle 38 * media selection and NWAY support here since there is no MII 39 * interface. However the logical operations are roughly the same, 40 * and the alternative is to create a fake MII interface in the driver, 41 * which is harder to do. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/malloc.h> 48 #include <sys/socket.h> 49 #include <sys/errno.h> 50 #include <sys/module.h> 51 #include <sys/bus.h> 52 53 #include <net/if.h> 54 #include <net/if_arp.h> 55 #include <net/if_media.h> 56 57 #include <dev/mii/mii.h> 58 #include <dev/mii/miivar.h> 59 #include <dev/mii/miidevs.h> 60 61 #include <machine/clock.h> 62 #include <machine/bus_pio.h> 63 #include <machine/bus_memio.h> 64 #include <machine/bus.h> 65 #include <machine/resource.h> 66 #include <sys/bus.h> 67 68 #include <pci/pcivar.h> 69 70 #include <pci/if_dcreg.h> 71 72 #include "miibus_if.h" 73 74 #if !defined(lint) 75 static const char rcsid[] = 76 "$FreeBSD$"; 77 #endif 78 79 #define DC_SETBIT(sc, reg, x) \ 80 CSR_WRITE_4(sc, reg, \ 81 CSR_READ_4(sc, reg) | x) 82 83 #define DC_CLRBIT(sc, reg, x) \ 84 CSR_WRITE_4(sc, reg, \ 85 CSR_READ_4(sc, reg) & ~x) 86 87 #define MIIF_AUTOTIMEOUT 0x0004 88 89 /* 90 * This is the subsystem ID for the built-in 21143 ethernet 91 * in several Compaq Presario systems. Apparently these are 92 * 10Mbps only, so we need to treat them specially. 93 */ 94 #define COMPAQ_PRESARIO_ID 0xb0bb0e11 95 96 static int dcphy_probe __P((device_t)); 97 static int dcphy_attach __P((device_t)); 98 static int dcphy_detach __P((device_t)); 99 100 static device_method_t dcphy_methods[] = { 101 /* device interface */ 102 DEVMETHOD(device_probe, dcphy_probe), 103 DEVMETHOD(device_attach, dcphy_attach), 104 DEVMETHOD(device_detach, dcphy_detach), 105 DEVMETHOD(device_shutdown, bus_generic_shutdown), 106 { 0, 0 } 107 }; 108 109 static devclass_t dcphy_devclass; 110 111 static driver_t dcphy_driver = { 112 "dcphy", 113 dcphy_methods, 114 sizeof(struct mii_softc) 115 }; 116 117 DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0); 118 119 int dcphy_service __P((struct mii_softc *, struct mii_data *, int)); 120 void dcphy_status __P((struct mii_softc *)); 121 static int dcphy_auto __P((struct mii_softc *, int)); 122 static void dcphy_reset __P((struct mii_softc *)); 123 124 static int dcphy_probe(dev) 125 device_t dev; 126 { 127 struct mii_attach_args *ma; 128 129 ma = device_get_ivars(dev); 130 131 /* 132 * The dc driver will report the 21143 vendor and device 133 * ID to let us know that it wants us to attach. 134 */ 135 if (ma->mii_id1 != DC_VENDORID_DEC || 136 ma->mii_id2 != DC_DEVICEID_21143) 137 return(ENXIO); 138 139 device_set_desc(dev, "Intel 21143 NWAY media interface"); 140 141 return (0); 142 } 143 144 static int dcphy_attach(dev) 145 device_t dev; 146 { 147 struct mii_softc *sc; 148 struct mii_attach_args *ma; 149 struct mii_data *mii; 150 struct dc_softc *dc_sc; 151 152 sc = device_get_softc(dev); 153 ma = device_get_ivars(dev); 154 sc->mii_dev = device_get_parent(dev); 155 mii = device_get_softc(sc->mii_dev); 156 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 157 158 sc->mii_inst = mii->mii_instance; 159 sc->mii_phy = ma->mii_phyno; 160 sc->mii_service = dcphy_service; 161 sc->mii_pdata = mii; 162 163 sc->mii_flags |= MIIF_NOISOLATE; 164 mii->mii_instance++; 165 166 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 167 168 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 169 BMCR_ISO); 170 171 /*dcphy_reset(sc);*/ 172 dc_sc = mii->mii_ifp->if_softc; 173 CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); 174 CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0); 175 176 switch(pci_read_config(device_get_parent(sc->mii_dev), 177 DC_PCI_CSID, 4)) { 178 case COMPAQ_PRESARIO_ID: 179 /* Example of how to only allow 10Mbps modes. */ 180 sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX; 181 break; 182 default: 183 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, 184 sc->mii_inst), BMCR_LOOP|BMCR_S100); 185 186 sc->mii_capabilities = 187 BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX| 188 BMSR_10TFDX|BMSR_10THDX; 189 break; 190 } 191 192 sc->mii_capabilities &= ma->mii_capmask; 193 device_printf(dev, " "); 194 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) 195 printf("no media present"); 196 else 197 mii_add_media(mii, sc->mii_capabilities, sc->mii_inst); 198 printf("\n"); 199 #undef ADD 200 201 MIIBUS_MEDIAINIT(sc->mii_dev); 202 return(0); 203 } 204 205 static int dcphy_detach(dev) 206 device_t dev; 207 { 208 struct mii_softc *sc; 209 struct mii_data *mii; 210 211 sc = device_get_softc(dev); 212 mii = device_get_softc(device_get_parent(dev)); 213 sc->mii_dev = NULL; 214 LIST_REMOVE(sc, mii_list); 215 216 return(0); 217 } 218 219 int 220 dcphy_service(sc, mii, cmd) 221 struct mii_softc *sc; 222 struct mii_data *mii; 223 int cmd; 224 { 225 struct dc_softc *dc_sc; 226 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 227 int reg; 228 u_int32_t mode; 229 230 dc_sc = mii->mii_ifp->if_softc; 231 232 switch (cmd) { 233 case MII_POLLSTAT: 234 /* 235 * If we're not polling our PHY instance, just return. 236 */ 237 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 238 return (0); 239 } 240 break; 241 242 case MII_MEDIACHG: 243 /* 244 * If the media indicates a different PHY instance, 245 * isolate ourselves. 246 */ 247 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 248 return (0); 249 } 250 251 /* 252 * If the interface is not up, don't do anything. 253 */ 254 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 255 break; 256 257 sc->mii_flags = 0; 258 mii->mii_media_active = IFM_NONE; 259 mode = CSR_READ_4(dc_sc, DC_NETCFG); 260 mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL| 261 DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL); 262 263 switch (IFM_SUBTYPE(ife->ifm_media)) { 264 case IFM_AUTO: 265 /*dcphy_reset(sc);*/ 266 (void) dcphy_auto(sc, 0); 267 break; 268 case IFM_100_T4: 269 /* 270 * XXX Not supported as a manual setting right now. 271 */ 272 return (EINVAL); 273 case IFM_100_TX: 274 dcphy_reset(sc); 275 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 276 mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS| 277 DC_NETCFG_SCRAMBLER; 278 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 279 mode |= DC_NETCFG_FULLDUPLEX; 280 else 281 mode &= ~DC_NETCFG_FULLDUPLEX; 282 CSR_WRITE_4(dc_sc, DC_NETCFG, mode); 283 break; 284 case IFM_10_T: 285 DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); 286 DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF); 287 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 288 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D); 289 else 290 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F); 291 DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); 292 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 293 mode &= ~DC_NETCFG_PORTSEL; 294 mode |= DC_NETCFG_SPEEDSEL; 295 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 296 mode |= DC_NETCFG_FULLDUPLEX; 297 else 298 mode &= ~DC_NETCFG_FULLDUPLEX; 299 CSR_WRITE_4(dc_sc, DC_NETCFG, mode); 300 break; 301 default: 302 return(EINVAL); 303 break; 304 } 305 break; 306 307 case MII_TICK: 308 /* 309 * If we're not currently selected, just return. 310 */ 311 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 312 return (0); 313 314 /* 315 * Only used for autonegotiation. 316 */ 317 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 318 return (0); 319 320 /* 321 * Is the interface even up? 322 */ 323 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 324 return (0); 325 326 if (sc->mii_flags & MIIF_DOINGAUTO) { 327 if (++sc->mii_ticks != 5) 328 return(0); 329 else { 330 sc->mii_ticks = 0; 331 sc->mii_flags &= ~MIIF_DOINGAUTO; 332 sc->mii_flags |= MIIF_AUTOTIMEOUT; 333 } 334 } 335 336 sc->mii_flags &= ~MIIF_DOINGAUTO; 337 338 /* 339 * Check to see if we have link. If we do, we don't 340 * need to restart the autonegotiation process. Read 341 * the BMSR twice in case it's latched. 342 */ 343 reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & 344 (DC_TSTAT_LS10|DC_TSTAT_LS100); 345 346 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX && 347 !(reg & DC_TSTAT_LS100)) { 348 if (sc->mii_flags & MIIF_AUTOTIMEOUT) { 349 sc->mii_flags &= ~MIIF_AUTOTIMEOUT; 350 break; 351 } else 352 return(0); 353 } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T && 354 !(reg & DC_TSTAT_LS10)) { 355 if (sc->mii_flags & MIIF_AUTOTIMEOUT) { 356 sc->mii_flags &= ~MIIF_AUTOTIMEOUT; 357 break; 358 } else 359 return(0); 360 } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE && 361 (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))) { 362 if (sc->mii_flags & MIIF_AUTOTIMEOUT) { 363 sc->mii_flags &= ~MIIF_AUTOTIMEOUT; 364 break; 365 } else 366 return(0); 367 } else if (CSR_READ_4(dc_sc, DC_ISR) & DC_ISR_LINKGOOD) { 368 if (sc->mii_flags & MIIF_AUTOTIMEOUT) { 369 sc->mii_flags &= ~MIIF_AUTOTIMEOUT; 370 break; 371 } else 372 return(0); 373 } 374 375 sc->mii_ticks = 0; 376 /*dcphy_reset(sc);*/ 377 dcphy_auto(sc, 0); 378 379 break; 380 } 381 382 /* Update the media status. */ 383 dcphy_status(sc); 384 385 /* Callback if something changed. */ 386 if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { 387 MIIBUS_STATCHG(sc->mii_dev); 388 sc->mii_active = mii->mii_media_active; 389 } 390 return (0); 391 } 392 393 void 394 dcphy_status(sc) 395 struct mii_softc *sc; 396 { 397 struct mii_data *mii = sc->mii_pdata; 398 int reg, anlpar; 399 struct dc_softc *dc_sc; 400 401 dc_sc = mii->mii_ifp->if_softc; 402 403 mii->mii_media_status = IFM_AVALID; 404 mii->mii_media_active = IFM_ETHER; 405 406 reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & 407 (DC_TSTAT_LS10|DC_TSTAT_LS100); 408 409 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) 410 mii->mii_media_status |= IFM_ACTIVE; 411 412 if (sc->mii_flags & MIIF_DOINGAUTO) { 413 mii->mii_media_active |= IFM_NONE; 414 return; 415 } 416 417 if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL && 418 CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) { 419 /* Erg, still trying, I guess... */ 420 if ((CSR_READ_4(dc_sc, DC_10BTSTAT) & 421 DC_ASTAT_AUTONEGCMP) != DC_ASTAT_AUTONEGCMP) { 422 mii->mii_media_active |= IFM_NONE; 423 return; 424 } 425 426 if (CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_LP_CAN_NWAY) { 427 anlpar = CSR_READ_4(dc_sc, DC_10BTSTAT) >> 16; 428 if (anlpar & ANLPAR_T4 && 429 sc->mii_capabilities & BMSR_100TXHDX) 430 mii->mii_media_active |= IFM_100_T4; 431 else if (anlpar & ANLPAR_TX_FD && 432 sc->mii_capabilities & BMSR_100TXHDX) 433 mii->mii_media_active |= IFM_100_TX|IFM_FDX; 434 else if (anlpar & ANLPAR_TX && 435 sc->mii_capabilities & BMSR_100TXHDX) 436 mii->mii_media_active |= IFM_100_TX; 437 else if (anlpar & ANLPAR_10_FD) 438 mii->mii_media_active |= IFM_10_T|IFM_FDX; 439 else if (anlpar & ANLPAR_10) 440 mii->mii_media_active |= IFM_10_T; 441 else 442 mii->mii_media_active |= IFM_NONE; 443 if (DC_IS_INTEL(dc_sc)) 444 DC_CLRBIT(dc_sc, DC_10BTCTRL, 445 DC_TCTL_AUTONEGENBL); 446 return; 447 } 448 /* 449 * If the other side doesn't support NWAY, then the 450 * best we can do is determine if we have a 10Mbps or 451 * 100Mbps link. There's no way to know if the link 452 * is full or half duplex, so we default to half duplex 453 * and hope that the user is clever enough to manually 454 * change the media settings if we're wrong. 455 */ 456 if (!(reg & DC_TSTAT_LS100)) 457 mii->mii_media_active |= IFM_100_TX; 458 else if (!(reg & DC_TSTAT_LS10)) 459 mii->mii_media_active |= IFM_10_T; 460 else 461 mii->mii_media_active |= IFM_NONE; 462 if (DC_IS_INTEL(dc_sc)) 463 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 464 return; 465 } 466 467 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SCRAMBLER) 468 mii->mii_media_active |= IFM_100_TX; 469 else 470 mii->mii_media_active |= IFM_10_T; 471 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) 472 mii->mii_media_active |= IFM_FDX; 473 474 return; 475 } 476 477 static int 478 dcphy_auto(mii, waitfor) 479 struct mii_softc *mii; 480 int waitfor; 481 { 482 int i; 483 struct dc_softc *sc; 484 485 sc = mii->mii_pdata->mii_ifp->if_softc; 486 487 if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) { 488 DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); 489 DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); 490 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); 491 if (mii->mii_capabilities & BMSR_100TXHDX) 492 CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF); 493 else 494 CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF); 495 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); 496 DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); 497 DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE); 498 } 499 500 if (waitfor) { 501 /* Wait 500ms for it to complete. */ 502 for (i = 0; i < 500; i++) { 503 if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) 504 == DC_ASTAT_AUTONEGCMP) 505 return(0); 506 DELAY(1000); 507 } 508 /* 509 * Don't need to worry about clearing MIIF_DOINGAUTO. 510 * If that's set, a timeout is pending, and it will 511 * clear the flag. 512 */ 513 return(EIO); 514 } 515 516 /* 517 * Just let it finish asynchronously. This is for the benefit of 518 * the tick handler driving autonegotiation. Don't want 500ms 519 * delays all the time while the system is running! 520 */ 521 if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) 522 mii->mii_flags |= MIIF_DOINGAUTO; 523 524 return(EJUSTRETURN); 525 } 526 527 static void 528 dcphy_reset(mii) 529 struct mii_softc *mii; 530 { 531 struct dc_softc *sc; 532 533 sc = mii->mii_pdata->mii_ifp->if_softc; 534 535 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); 536 DELAY(1000); 537 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); 538 539 return; 540 } 541 542