rlswitch.c revision 221407
1193579Sraj/*- 2193579Sraj * Copyright (c) 1997, 1998, 1999 3193579Sraj * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4193579Sraj * Copyright (c) 2006 Bernd Walter. All rights reserved. 5193579Sraj * 6193579Sraj * Redistribution and use in source and binary forms, with or without 7193579Sraj * modification, are permitted provided that the following conditions 8193579Sraj * are met: 9193579Sraj * 1. Redistributions of source code must retain the above copyright 10193579Sraj * notice, this list of conditions and the following disclaimer. 11193579Sraj * 2. Redistributions in binary form must reproduce the above copyright 12193579Sraj * notice, this list of conditions and the following disclaimer in the 13193579Sraj * documentation and/or other materials provided with the distribution. 14193579Sraj * 3. All advertising materials mentioning features or use of this software 15193579Sraj * must display the following acknowledgement: 16193579Sraj * This product includes software developed by Bill Paul. 17193579Sraj * 4. Neither the name of the author nor the names of any co-contributors 18193579Sraj * may be used to endorse or promote products derived from this software 19193579Sraj * without specific prior written permission. 20193579Sraj * 21193579Sraj * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22193579Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23193579Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24193579Sraj * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25193579Sraj * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26193579Sraj * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27193579Sraj * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28193579Sraj * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29193579Sraj * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30193579Sraj * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31193579Sraj * THE POSSIBILITY OF SUCH DAMAGE. 32193579Sraj */ 33193579Sraj 34193579Sraj#include <sys/cdefs.h> 35193579Sraj__FBSDID("$FreeBSD: head/sys/dev/mii/rlswitch.c 221407 2011-05-03 19:51:29Z marius $"); 36193579Sraj 37193579Sraj/* 38193579Sraj * driver for RealTek 8305 pseudo PHYs 39193579Sraj */ 40193579Sraj 41193579Sraj#include <sys/param.h> 42193579Sraj#include <sys/systm.h> 43193579Sraj#include <sys/kernel.h> 44193579Sraj#include <sys/module.h> 45193579Sraj#include <sys/socket.h> 46193579Sraj#include <sys/bus.h> 47193579Sraj 48193579Sraj#include <net/if.h> 49193579Sraj#include <net/if_arp.h> 50193579Sraj#include <net/if_media.h> 51193579Sraj 52193579Sraj#include <dev/mii/mii.h> 53209908Sraj#include <dev/mii/miivar.h> 54193579Sraj#include "miidevs.h" 55193579Sraj 56193579Sraj#include <machine/bus.h> 57193579Sraj#include <pci/if_rlreg.h> 58193579Sraj 59193579Sraj#include "miibus_if.h" 60193579Sraj 61194101Sraj//#define RL_DEBUG 62193579Sraj#define RL_VLAN 63193579Sraj 64193579Srajstatic int rlswitch_probe(device_t); 65193579Srajstatic int rlswitch_attach(device_t); 66193579Sraj 67193579Srajstatic device_method_t rlswitch_methods[] = { 68193579Sraj /* device interface */ 69193579Sraj DEVMETHOD(device_probe, rlswitch_probe), 70193579Sraj DEVMETHOD(device_attach, rlswitch_attach), 71193579Sraj DEVMETHOD(device_detach, mii_phy_detach), 72193579Sraj DEVMETHOD(device_shutdown, bus_generic_shutdown), 73193579Sraj { 0, 0 } 74193579Sraj}; 75193579Sraj 76193579Srajstatic devclass_t rlswitch_devclass; 77193579Sraj 78193579Srajstatic driver_t rlswitch_driver = { 79193579Sraj "rlswitch", 80193579Sraj rlswitch_methods, 81193579Sraj sizeof(struct mii_softc) 82193579Sraj}; 83193579Sraj 84193579SrajDRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0); 85193579Sraj 86193579Srajstatic int rlswitch_service(struct mii_softc *, struct mii_data *, int); 87193579Srajstatic void rlswitch_status(struct mii_softc *); 88193579Sraj 89193579Sraj#ifdef RL_DEBUG 90193579Srajstatic void rlswitch_phydump(device_t dev); 91193579Sraj#endif 92193579Sraj 93193579Srajstatic const struct mii_phydesc rlswitches[] = { 94193579Sraj MII_PHY_DESC(REALTEK, RTL8305SC), 95193579Sraj MII_PHY_END 96193579Sraj}; 97193579Sraj 98193579Srajstatic const struct mii_phy_funcs rlswitch_funcs = { 99193579Sraj rlswitch_service, 100193579Sraj rlswitch_status, 101193579Sraj mii_phy_reset 102193579Sraj}; 103193579Sraj 104193579Srajstatic int 105193579Srajrlswitch_probe(device_t dev) 106193579Sraj{ 107193579Sraj int rv; 108193579Sraj 109193579Sraj rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); 110193579Sraj if (rv <= 0) 111193579Sraj return (rv); 112193579Sraj 113193579Sraj return (ENXIO); 114193579Sraj} 115193579Sraj 116193579Srajstatic int 117193579Srajrlswitch_attach(device_t dev) 118193579Sraj{ 119193579Sraj struct mii_softc *sc; 120193579Sraj 121193579Sraj sc = device_get_softc(dev); 122193579Sraj 123193579Sraj /* 124193579Sraj * We handle all pseudo PHYs in a single instance. 125193579Sraj */ 126193579Sraj mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 127193579Sraj &rlswitch_funcs, 0); 128193579Sraj 129193579Sraj sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask; 130193579Sraj device_printf(dev, " "); 131193579Sraj mii_phy_add_media(sc); 132193579Sraj printf("\n"); 133193579Sraj#ifdef RL_DEBUG 134193579Sraj rlswitch_phydump(dev); 135193579Sraj#endif 136193579Sraj 137193579Sraj#ifdef RL_VLAN 138193579Sraj int val; 139193579Sraj 140193579Sraj /* Global Control 0 */ 141193579Sraj val = 0; 142193579Sraj val |= 0 << 10; /* enable 802.1q VLAN Tag support */ 143193579Sraj val |= 0 << 9; /* enable VLAN ingress filtering */ 144193579Sraj val |= 1 << 8; /* disable VLAN tag admit control */ 145193579Sraj val |= 1 << 6; /* internal use */ 146193579Sraj val |= 1 << 5; /* internal use */ 147193579Sraj val |= 1 << 4; /* internal use */ 148193579Sraj val |= 1 << 3; /* internal use */ 149193579Sraj val |= 1 << 1; /* reserved */ 150193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); 151193579Sraj 152193579Sraj /* Global Control 2 */ 153193579Sraj val = 0; 154193579Sraj val |= 1 << 15; /* reserved */ 155193579Sraj val |= 0 << 14; /* enable 1552 Bytes support */ 156209908Sraj val |= 1 << 13; /* enable broadcast input drop */ 157193579Sraj val |= 1 << 12; /* forward reserved control frames */ 158193579Sraj val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ 159193579Sraj val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ 160193579Sraj val |= 1 << 9; /* enable 48 pass 1 */ 161193579Sraj val |= 0 << 8; /* enable VLAN */ 162193579Sraj val |= 1 << 7; /* reserved */ 163193579Sraj val |= 1 << 6; /* enable defer */ 164193579Sraj val |= 1 << 5; /* 43ms LED blink time */ 165193579Sraj val |= 3 << 3; /* 16:1 queue weight */ 166193579Sraj val |= 1 << 2; /* disable broadcast storm control */ 167193579Sraj val |= 1 << 1; /* enable power-on LED blinking */ 168193579Sraj val |= 1 << 0; /* reserved */ 169193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); 170193579Sraj 171193579Sraj /* Port 0 Control Register 0 */ 172193579Sraj val = 0; 173193579Sraj val |= 1 << 15; /* reserved */ 174193579Sraj val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 175193579Sraj val |= 1 << 10; /* disable 802.1p priority classification */ 176193579Sraj val |= 1 << 9; /* disable diffserv priority classification */ 177193579Sraj val |= 1 << 6; /* internal use */ 178193579Sraj val |= 3 << 4; /* internal use */ 179193579Sraj val |= 1 << 3; /* internal use */ 180193579Sraj val |= 1 << 2; /* internal use */ 181193579Sraj val |= 1 << 0; /* remove VLAN tags on output */ 182193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); 183193579Sraj 184193579Sraj /* Port 1 Control Register 0 */ 185193579Sraj val = 0; 186193579Sraj val |= 1 << 15; /* reserved */ 187193579Sraj val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 188193579Sraj val |= 1 << 10; /* disable 802.1p priority classification */ 189193579Sraj val |= 1 << 9; /* disable diffserv priority classification */ 190193579Sraj val |= 1 << 6; /* internal use */ 191193579Sraj val |= 3 << 4; /* internal use */ 192193579Sraj val |= 1 << 3; /* internal use */ 193193579Sraj val |= 1 << 2; /* internal use */ 194193579Sraj val |= 1 << 0; /* remove VLAN tags on output */ 195193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); 196193579Sraj 197193579Sraj /* Port 2 Control Register 0 */ 198193579Sraj val = 0; 199193579Sraj val |= 1 << 15; /* reserved */ 200193579Sraj val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 201193579Sraj val |= 1 << 10; /* disable 802.1p priority classification */ 202193579Sraj val |= 1 << 9; /* disable diffserv priority classification */ 203193579Sraj val |= 1 << 6; /* internal use */ 204193579Sraj val |= 3 << 4; /* internal use */ 205193579Sraj val |= 1 << 3; /* internal use */ 206209908Sraj val |= 1 << 2; /* internal use */ 207193579Sraj val |= 1 << 0; /* remove VLAN tags on output */ 208193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); 209193579Sraj 210193579Sraj /* Port 3 Control Register 0 */ 211193579Sraj val = 0; 212209908Sraj val |= 1 << 15; /* reserved */ 213209908Sraj val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 214193579Sraj val |= 1 << 10; /* disable 802.1p priority classification */ 215193579Sraj val |= 1 << 9; /* disable diffserv priority classification */ 216193579Sraj val |= 1 << 6; /* internal use */ 217193579Sraj val |= 3 << 4; /* internal use */ 218193579Sraj val |= 1 << 3; /* internal use */ 219193579Sraj val |= 1 << 2; /* internal use */ 220193579Sraj val |= 1 << 0; /* remove VLAN tags on output */ 221193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); 222193579Sraj 223193579Sraj /* Port 4 (system port) Control Register 0 */ 224193579Sraj val = 0; 225193579Sraj val |= 1 << 15; /* reserved */ 226193579Sraj val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ 227193579Sraj val |= 1 << 10; /* disable 802.1p priority classification */ 228193579Sraj val |= 1 << 9; /* disable diffserv priority classification */ 229193579Sraj val |= 1 << 6; /* internal use */ 230193579Sraj val |= 3 << 4; /* internal use */ 231193579Sraj val |= 1 << 3; /* internal use */ 232193579Sraj val |= 1 << 2; /* internal use */ 233193579Sraj val |= 2 << 0; /* add VLAN tags for untagged packets on output */ 234193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); 235193579Sraj 236193579Sraj /* Port 0 Control Register 1 and VLAN A */ 237193579Sraj val = 0; 238193579Sraj val |= 0x0 << 12; /* Port 0 VLAN Index */ 239193579Sraj val |= 1 << 11; /* internal use */ 240193579Sraj val |= 1 << 10; /* internal use */ 241193579Sraj val |= 1 << 9; /* internal use */ 242193579Sraj val |= 1 << 7; /* internal use */ 243193579Sraj val |= 1 << 6; /* internal use */ 244193579Sraj val |= 0x11 << 0; /* VLAN A membership */ 245193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); 246193579Sraj 247193579Sraj /* Port 0 Control Register 2 and VLAN A */ 248193579Sraj val = 0; 249193579Sraj val |= 1 << 15; /* internal use */ 250193579Sraj val |= 1 << 14; /* internal use */ 251193579Sraj val |= 1 << 13; /* internal use */ 252193579Sraj val |= 1 << 12; /* internal use */ 253193579Sraj val |= 0x100 << 0; /* VLAN A ID */ 254193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); 255193579Sraj 256193579Sraj /* Port 1 Control Register 1 and VLAN B */ 257193579Sraj val = 0; 258193579Sraj val |= 0x1 << 12; /* Port 1 VLAN Index */ 259193579Sraj val |= 1 << 11; /* internal use */ 260193579Sraj val |= 1 << 10; /* internal use */ 261193579Sraj val |= 1 << 9; /* internal use */ 262193579Sraj val |= 1 << 7; /* internal use */ 263193579Sraj val |= 1 << 6; /* internal use */ 264193579Sraj val |= 0x12 << 0; /* VLAN B membership */ 265193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); 266193579Sraj 267193579Sraj /* Port 1 Control Register 2 and VLAN B */ 268193579Sraj val = 0; 269193579Sraj val |= 1 << 15; /* internal use */ 270193579Sraj val |= 1 << 14; /* internal use */ 271209908Sraj val |= 1 << 13; /* internal use */ 272209908Sraj val |= 1 << 12; /* internal use */ 273193579Sraj val |= 0x101 << 0; /* VLAN B ID */ 274193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); 275193579Sraj 276193579Sraj /* Port 2 Control Register 1 and VLAN C */ 277193579Sraj val = 0; 278193579Sraj val |= 0x2 << 12; /* Port 2 VLAN Index */ 279193579Sraj val |= 1 << 11; /* internal use */ 280193579Sraj val |= 1 << 10; /* internal use */ 281193579Sraj val |= 1 << 9; /* internal use */ 282193579Sraj val |= 1 << 7; /* internal use */ 283193579Sraj val |= 1 << 6; /* internal use */ 284193579Sraj val |= 0x14 << 0; /* VLAN C membership */ 285193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); 286193579Sraj 287193579Sraj /* Port 2 Control Register 2 and VLAN C */ 288193579Sraj val = 0; 289193579Sraj val |= 1 << 15; /* internal use */ 290193579Sraj val |= 1 << 14; /* internal use */ 291209908Sraj val |= 1 << 13; /* internal use */ 292209908Sraj val |= 1 << 12; /* internal use */ 293209908Sraj val |= 0x102 << 0; /* VLAN C ID */ 294209908Sraj MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); 295193579Sraj 296209908Sraj /* Port 3 Control Register 1 and VLAN D */ 297209908Sraj val = 0; 298209908Sraj val |= 0x3 << 12; /* Port 3 VLAN Index */ 299209908Sraj val |= 1 << 11; /* internal use */ 300193579Sraj val |= 1 << 10; /* internal use */ 301193579Sraj val |= 1 << 9; /* internal use */ 302193579Sraj val |= 1 << 7; /* internal use */ 303193579Sraj val |= 1 << 6; /* internal use */ 304193579Sraj val |= 0x18 << 0; /* VLAN D membership */ 305193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); 306193579Sraj 307193579Sraj /* Port 3 Control Register 2 and VLAN D */ 308193579Sraj val = 0; 309193579Sraj val |= 1 << 15; /* internal use */ 310193579Sraj val |= 1 << 14; /* internal use */ 311193579Sraj val |= 1 << 13; /* internal use */ 312193579Sraj val |= 1 << 12; /* internal use */ 313193579Sraj val |= 0x103 << 0; /* VLAN D ID */ 314193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); 315193579Sraj 316193579Sraj /* Port 4 Control Register 1 and VLAN E */ 317193579Sraj val = 0; 318193579Sraj val |= 0x0 << 12; /* Port 4 VLAN Index */ 319193579Sraj val |= 1 << 11; /* internal use */ 320193579Sraj val |= 1 << 10; /* internal use */ 321193579Sraj val |= 1 << 9; /* internal use */ 322193579Sraj val |= 1 << 7; /* internal use */ 323193579Sraj val |= 1 << 6; /* internal use */ 324193579Sraj val |= 0 << 0; /* VLAN E membership */ 325193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); 326193579Sraj 327193579Sraj /* Port 4 Control Register 2 and VLAN E */ 328193579Sraj val = 0; 329193579Sraj val |= 1 << 15; /* internal use */ 330193579Sraj val |= 1 << 14; /* internal use */ 331193579Sraj val |= 1 << 13; /* internal use */ 332193579Sraj val |= 1 << 12; /* internal use */ 333193579Sraj val |= 0x104 << 0; /* VLAN E ID */ 334193579Sraj MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); 335193579Sraj#endif 336193579Sraj 337193579Sraj#ifdef RL_DEBUG 338193579Sraj rlswitch_phydump(dev); 339193579Sraj#endif 340193579Sraj MIIBUS_MEDIAINIT(sc->mii_dev); 341193579Sraj return (0); 342193579Sraj} 343193579Sraj 344193579Srajstatic int 345193579Srajrlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 346193579Sraj{ 347193579Sraj 348193579Sraj switch (cmd) { 349193579Sraj case MII_POLLSTAT: 350193579Sraj break; 351193579Sraj 352193579Sraj case MII_MEDIACHG: 353193579Sraj break; 354193579Sraj 355193579Sraj case MII_TICK: 356193579Sraj /* 357193579Sraj * Is the interface even up? 358193579Sraj */ 359193579Sraj if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 360193579Sraj return (0); 361193579Sraj break; 362193579Sraj } 363193579Sraj 364193579Sraj /* Update the media status. */ 365193579Sraj PHY_STATUS(sc); 366193579Sraj 367193579Sraj /* Callback if something changed. */ 368193579Sraj // mii_phy_update(sc, cmd); 369193579Sraj return (0); 370193579Sraj} 371193579Sraj 372193579Srajstatic void 373193579Srajrlswitch_status(struct mii_softc *phy) 374193579Sraj{ 375193579Sraj struct mii_data *mii = phy->mii_pdata; 376193579Sraj 377193579Sraj mii->mii_media_status = IFM_AVALID; 378193579Sraj mii->mii_media_active = IFM_ETHER; 379193579Sraj mii->mii_media_status |= IFM_ACTIVE; 380193579Sraj mii->mii_media_active |= 381193579Sraj IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy); 382193579Sraj} 383193579Sraj 384193579Sraj#ifdef RL_DEBUG 385193579Srajstatic void 386193579Srajrlswitch_phydump(device_t dev) { 387193579Sraj int phy, reg, val; 388193579Sraj struct mii_softc *sc; 389193579Sraj 390193579Sraj sc = device_get_softc(dev); 391193579Sraj device_printf(dev, "rlswitchphydump\n"); 392193579Sraj for (phy = 0; phy <= 5; phy++) { 393193579Sraj printf("PHY%i:", phy); 394193579Sraj for (reg = 0; reg <= 31; reg++) { 395193579Sraj val = MIIBUS_READREG(sc->mii_dev, phy, reg); 396193579Sraj printf(" 0x%x", val); 397193579Sraj } 398193579Sraj printf("\n"); 399193579Sraj } 400193579Sraj} 401193579Sraj#endif 402193579Sraj