rlswitch.c revision 227908
1165782Sticso/*- 2165782Sticso * Copyright (c) 1997, 1998, 1999 3165782Sticso * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4165782Sticso * Copyright (c) 2006 Bernd Walter. All rights reserved. 5165782Sticso * 6165782Sticso * Redistribution and use in source and binary forms, with or without 7165782Sticso * modification, are permitted provided that the following conditions 8165782Sticso * are met: 9165782Sticso * 1. Redistributions of source code must retain the above copyright 10165782Sticso * notice, this list of conditions and the following disclaimer. 11165782Sticso * 2. Redistributions in binary form must reproduce the above copyright 12165782Sticso * notice, this list of conditions and the following disclaimer in the 13165782Sticso * documentation and/or other materials provided with the distribution. 14165782Sticso * 3. All advertising materials mentioning features or use of this software 15165782Sticso * must display the following acknowledgement: 16165782Sticso * This product includes software developed by Bill Paul. 17165782Sticso * 4. Neither the name of the author nor the names of any co-contributors 18165782Sticso * may be used to endorse or promote products derived from this software 19165782Sticso * without specific prior written permission. 20165782Sticso * 21165782Sticso * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22165782Sticso * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23165782Sticso * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24165782Sticso * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25165782Sticso * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26165782Sticso * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27165782Sticso * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28165782Sticso * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29165782Sticso * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30165782Sticso * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31165782Sticso * THE POSSIBILITY OF SUCH DAMAGE. 32165782Sticso */ 33165782Sticso 34165782Sticso#include <sys/cdefs.h> 35165782Sticso__FBSDID("$FreeBSD: head/sys/dev/mii/rlswitch.c 227908 2011-11-23 20:27:26Z marius $"); 36165782Sticso 37165782Sticso/* 38165782Sticso * driver for RealTek 8305 pseudo PHYs 39165782Sticso */ 40165782Sticso 41165782Sticso#include <sys/param.h> 42165782Sticso#include <sys/systm.h> 43165782Sticso#include <sys/kernel.h> 44165782Sticso#include <sys/module.h> 45165782Sticso#include <sys/socket.h> 46165782Sticso#include <sys/bus.h> 47165782Sticso 48165782Sticso#include <net/if.h> 49165782Sticso#include <net/if_arp.h> 50165782Sticso#include <net/if_media.h> 51165782Sticso 52165782Sticso#include <dev/mii/mii.h> 53165782Sticso#include <dev/mii/miivar.h> 54165782Sticso#include "miidevs.h" 55165782Sticso 56165782Sticso#include <machine/bus.h> 57165782Sticso#include <pci/if_rlreg.h> 58165782Sticso 59165782Sticso#include "miibus_if.h" 60165782Sticso 61165782Sticso//#define RL_DEBUG 62165782Sticso#define RL_VLAN 63165782Sticso 64165782Sticsostatic int rlswitch_probe(device_t); 65165782Sticsostatic int rlswitch_attach(device_t); 66165782Sticso 67165782Sticsostatic device_method_t rlswitch_methods[] = { 68165782Sticso /* device interface */ 69165782Sticso DEVMETHOD(device_probe, rlswitch_probe), 70165782Sticso DEVMETHOD(device_attach, rlswitch_attach), 71165782Sticso DEVMETHOD(device_detach, mii_phy_detach), 72165782Sticso DEVMETHOD(device_shutdown, bus_generic_shutdown), 73227908Smarius DEVMETHOD_END 74165782Sticso}; 75165782Sticso 76165782Sticsostatic devclass_t rlswitch_devclass; 77165782Sticso 78165782Sticsostatic driver_t rlswitch_driver = { 79165782Sticso "rlswitch", 80165782Sticso rlswitch_methods, 81165782Sticso sizeof(struct mii_softc) 82165782Sticso}; 83165782Sticso 84165782SticsoDRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0); 85165782Sticso 86165782Sticsostatic int rlswitch_service(struct mii_softc *, struct mii_data *, int); 87165782Sticsostatic void rlswitch_status(struct mii_softc *); 88165782Sticso 89165782Sticso#ifdef RL_DEBUG 90165782Sticsostatic void rlswitch_phydump(device_t dev); 91165782Sticso#endif 92165782Sticso 93165782Sticsostatic const struct mii_phydesc rlswitches[] = { 94221407Smarius MII_PHY_DESC(REALTEK, RTL8305SC), 95165782Sticso MII_PHY_END 96165782Sticso}; 97165782Sticso 98221407Smariusstatic const struct mii_phy_funcs rlswitch_funcs = { 99221407Smarius rlswitch_service, 100221407Smarius rlswitch_status, 101221407Smarius mii_phy_reset 102221407Smarius}; 103221407Smarius 104165782Sticsostatic int 105165782Sticsorlswitch_probe(device_t dev) 106165782Sticso{ 107165782Sticso int rv; 108165782Sticso 109165782Sticso rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); 110165782Sticso if (rv <= 0) 111165782Sticso return (rv); 112165782Sticso 113165782Sticso return (ENXIO); 114165782Sticso} 115165782Sticso 116165782Sticsostatic int 117165782Sticsorlswitch_attach(device_t dev) 118165782Sticso{ 119165782Sticso struct mii_softc *sc; 120165782Sticso 121165782Sticso sc = device_get_softc(dev); 122165782Sticso 123213364Smarius /* 124213364Smarius * We handle all pseudo PHYs in a single instance. 125213364Smarius */ 126221407Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 127221407Smarius &rlswitch_funcs, 0); 128165782Sticso 129221407Smarius sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask; 130165782Sticso device_printf(dev, " "); 131165782Sticso mii_phy_add_media(sc); 132165782Sticso printf("\n"); 133165782Sticso#ifdef RL_DEBUG 134165782Sticso rlswitch_phydump(dev); 135165782Sticso#endif 136165782Sticso 137165782Sticso#ifdef RL_VLAN 138165782Sticso int val; 139165782Sticso 140165782Sticso /* Global Control 0 */ 141165782Sticso val = 0; 142165782Sticso val |= 0 << 10; /* enable 802.1q VLAN Tag support */ 143165782Sticso val |= 0 << 9; /* enable VLAN ingress filtering */ 144165782Sticso val |= 1 << 8; /* disable VLAN tag admit control */ 145165782Sticso val |= 1 << 6; /* internal use */ 146165782Sticso val |= 1 << 5; /* internal use */ 147165782Sticso val |= 1 << 4; /* internal use */ 148165782Sticso val |= 1 << 3; /* internal use */ 149165782Sticso val |= 1 << 1; /* reserved */ 150165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); 151165782Sticso 152165782Sticso /* Global Control 2 */ 153165782Sticso val = 0; 154165782Sticso val |= 1 << 15; /* reserved */ 155165782Sticso val |= 0 << 14; /* enable 1552 Bytes support */ 156165782Sticso val |= 1 << 13; /* enable broadcast input drop */ 157165782Sticso val |= 1 << 12; /* forward reserved control frames */ 158165782Sticso val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ 159165782Sticso val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ 160165782Sticso val |= 1 << 9; /* enable 48 pass 1 */ 161165782Sticso val |= 0 << 8; /* enable VLAN */ 162165782Sticso val |= 1 << 7; /* reserved */ 163165782Sticso val |= 1 << 6; /* enable defer */ 164165782Sticso val |= 1 << 5; /* 43ms LED blink time */ 165165782Sticso val |= 3 << 3; /* 16:1 queue weight */ 166165782Sticso val |= 1 << 2; /* disable broadcast storm control */ 167165782Sticso val |= 1 << 1; /* enable power-on LED blinking */ 168165782Sticso val |= 1 << 0; /* reserved */ 169165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); 170165782Sticso 171165782Sticso /* Port 0 Control Register 0 */ 172165782Sticso val = 0; 173165782Sticso val |= 1 << 15; /* reserved */ 174165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 175165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 176165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 177165782Sticso val |= 1 << 6; /* internal use */ 178165782Sticso val |= 3 << 4; /* internal use */ 179165782Sticso val |= 1 << 3; /* internal use */ 180165782Sticso val |= 1 << 2; /* internal use */ 181165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 182165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); 183165782Sticso 184165782Sticso /* Port 1 Control Register 0 */ 185165782Sticso val = 0; 186165782Sticso val |= 1 << 15; /* reserved */ 187165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 188165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 189165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 190165782Sticso val |= 1 << 6; /* internal use */ 191165782Sticso val |= 3 << 4; /* internal use */ 192165782Sticso val |= 1 << 3; /* internal use */ 193165782Sticso val |= 1 << 2; /* internal use */ 194165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 195165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); 196165782Sticso 197165782Sticso /* Port 2 Control Register 0 */ 198165782Sticso val = 0; 199165782Sticso val |= 1 << 15; /* reserved */ 200165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 201165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 202165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 203165782Sticso val |= 1 << 6; /* internal use */ 204165782Sticso val |= 3 << 4; /* internal use */ 205165782Sticso val |= 1 << 3; /* internal use */ 206165782Sticso val |= 1 << 2; /* internal use */ 207165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 208165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); 209165782Sticso 210165782Sticso /* Port 3 Control Register 0 */ 211165782Sticso val = 0; 212165782Sticso val |= 1 << 15; /* reserved */ 213165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 214165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 215165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 216165782Sticso val |= 1 << 6; /* internal use */ 217165782Sticso val |= 3 << 4; /* internal use */ 218165782Sticso val |= 1 << 3; /* internal use */ 219165782Sticso val |= 1 << 2; /* internal use */ 220165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 221165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); 222165782Sticso 223165782Sticso /* Port 4 (system port) Control Register 0 */ 224165782Sticso val = 0; 225165782Sticso val |= 1 << 15; /* reserved */ 226165782Sticso val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ 227165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 228165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 229165782Sticso val |= 1 << 6; /* internal use */ 230165782Sticso val |= 3 << 4; /* internal use */ 231165782Sticso val |= 1 << 3; /* internal use */ 232165782Sticso val |= 1 << 2; /* internal use */ 233165782Sticso val |= 2 << 0; /* add VLAN tags for untagged packets on output */ 234165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); 235165782Sticso 236165782Sticso /* Port 0 Control Register 1 and VLAN A */ 237165782Sticso val = 0; 238165782Sticso val |= 0x0 << 12; /* Port 0 VLAN Index */ 239165782Sticso val |= 1 << 11; /* internal use */ 240165782Sticso val |= 1 << 10; /* internal use */ 241165782Sticso val |= 1 << 9; /* internal use */ 242165782Sticso val |= 1 << 7; /* internal use */ 243165782Sticso val |= 1 << 6; /* internal use */ 244165782Sticso val |= 0x11 << 0; /* VLAN A membership */ 245165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); 246165782Sticso 247165782Sticso /* Port 0 Control Register 2 and VLAN A */ 248165782Sticso val = 0; 249165782Sticso val |= 1 << 15; /* internal use */ 250165782Sticso val |= 1 << 14; /* internal use */ 251165782Sticso val |= 1 << 13; /* internal use */ 252165782Sticso val |= 1 << 12; /* internal use */ 253165782Sticso val |= 0x100 << 0; /* VLAN A ID */ 254165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); 255165782Sticso 256165782Sticso /* Port 1 Control Register 1 and VLAN B */ 257165782Sticso val = 0; 258165782Sticso val |= 0x1 << 12; /* Port 1 VLAN Index */ 259165782Sticso val |= 1 << 11; /* internal use */ 260165782Sticso val |= 1 << 10; /* internal use */ 261165782Sticso val |= 1 << 9; /* internal use */ 262165782Sticso val |= 1 << 7; /* internal use */ 263165782Sticso val |= 1 << 6; /* internal use */ 264165782Sticso val |= 0x12 << 0; /* VLAN B membership */ 265165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); 266165782Sticso 267165782Sticso /* Port 1 Control Register 2 and VLAN B */ 268165782Sticso val = 0; 269165782Sticso val |= 1 << 15; /* internal use */ 270165782Sticso val |= 1 << 14; /* internal use */ 271165782Sticso val |= 1 << 13; /* internal use */ 272165782Sticso val |= 1 << 12; /* internal use */ 273165782Sticso val |= 0x101 << 0; /* VLAN B ID */ 274165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); 275165782Sticso 276165782Sticso /* Port 2 Control Register 1 and VLAN C */ 277165782Sticso val = 0; 278165782Sticso val |= 0x2 << 12; /* Port 2 VLAN Index */ 279165782Sticso val |= 1 << 11; /* internal use */ 280165782Sticso val |= 1 << 10; /* internal use */ 281165782Sticso val |= 1 << 9; /* internal use */ 282165782Sticso val |= 1 << 7; /* internal use */ 283165782Sticso val |= 1 << 6; /* internal use */ 284165782Sticso val |= 0x14 << 0; /* VLAN C membership */ 285165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); 286165782Sticso 287165782Sticso /* Port 2 Control Register 2 and VLAN C */ 288165782Sticso val = 0; 289165782Sticso val |= 1 << 15; /* internal use */ 290165782Sticso val |= 1 << 14; /* internal use */ 291165782Sticso val |= 1 << 13; /* internal use */ 292165782Sticso val |= 1 << 12; /* internal use */ 293165782Sticso val |= 0x102 << 0; /* VLAN C ID */ 294165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); 295165782Sticso 296165782Sticso /* Port 3 Control Register 1 and VLAN D */ 297165782Sticso val = 0; 298165782Sticso val |= 0x3 << 12; /* Port 3 VLAN Index */ 299165782Sticso val |= 1 << 11; /* internal use */ 300165782Sticso val |= 1 << 10; /* internal use */ 301165782Sticso val |= 1 << 9; /* internal use */ 302165782Sticso val |= 1 << 7; /* internal use */ 303165782Sticso val |= 1 << 6; /* internal use */ 304165782Sticso val |= 0x18 << 0; /* VLAN D membership */ 305165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); 306165782Sticso 307165782Sticso /* Port 3 Control Register 2 and VLAN D */ 308165782Sticso val = 0; 309165782Sticso val |= 1 << 15; /* internal use */ 310165782Sticso val |= 1 << 14; /* internal use */ 311165782Sticso val |= 1 << 13; /* internal use */ 312165782Sticso val |= 1 << 12; /* internal use */ 313165782Sticso val |= 0x103 << 0; /* VLAN D ID */ 314165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); 315165782Sticso 316165782Sticso /* Port 4 Control Register 1 and VLAN E */ 317165782Sticso val = 0; 318165782Sticso val |= 0x0 << 12; /* Port 4 VLAN Index */ 319165782Sticso val |= 1 << 11; /* internal use */ 320165782Sticso val |= 1 << 10; /* internal use */ 321165782Sticso val |= 1 << 9; /* internal use */ 322165782Sticso val |= 1 << 7; /* internal use */ 323165782Sticso val |= 1 << 6; /* internal use */ 324165782Sticso val |= 0 << 0; /* VLAN E membership */ 325165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); 326165782Sticso 327165782Sticso /* Port 4 Control Register 2 and VLAN E */ 328165782Sticso val = 0; 329165782Sticso val |= 1 << 15; /* internal use */ 330165782Sticso val |= 1 << 14; /* internal use */ 331165782Sticso val |= 1 << 13; /* internal use */ 332165782Sticso val |= 1 << 12; /* internal use */ 333165782Sticso val |= 0x104 << 0; /* VLAN E ID */ 334165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); 335165782Sticso#endif 336165782Sticso 337165782Sticso#ifdef RL_DEBUG 338165782Sticso rlswitch_phydump(dev); 339165782Sticso#endif 340165782Sticso MIIBUS_MEDIAINIT(sc->mii_dev); 341165782Sticso return (0); 342165782Sticso} 343165782Sticso 344165782Sticsostatic int 345165782Sticsorlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 346165782Sticso{ 347165782Sticso 348165782Sticso switch (cmd) { 349165782Sticso case MII_POLLSTAT: 350165782Sticso break; 351165782Sticso 352165782Sticso case MII_MEDIACHG: 353165782Sticso break; 354165782Sticso 355165782Sticso case MII_TICK: 356165782Sticso /* 357165782Sticso * Is the interface even up? 358165782Sticso */ 359165782Sticso if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 360165782Sticso return (0); 361165782Sticso break; 362165782Sticso } 363165782Sticso 364165782Sticso /* Update the media status. */ 365221407Smarius PHY_STATUS(sc); 366165782Sticso 367165782Sticso /* Callback if something changed. */ 368165782Sticso // mii_phy_update(sc, cmd); 369165782Sticso return (0); 370165782Sticso} 371165782Sticso 372165782Sticsostatic void 373165782Sticsorlswitch_status(struct mii_softc *phy) 374165782Sticso{ 375165782Sticso struct mii_data *mii = phy->mii_pdata; 376165782Sticso 377165782Sticso mii->mii_media_status = IFM_AVALID; 378165782Sticso mii->mii_media_active = IFM_ETHER; 379165782Sticso mii->mii_media_status |= IFM_ACTIVE; 380221407Smarius mii->mii_media_active |= 381221407Smarius IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy); 382165782Sticso} 383165782Sticso 384165782Sticso#ifdef RL_DEBUG 385165782Sticsostatic void 386165782Sticsorlswitch_phydump(device_t dev) { 387165782Sticso int phy, reg, val; 388165782Sticso struct mii_softc *sc; 389165782Sticso 390165782Sticso sc = device_get_softc(dev); 391165782Sticso device_printf(dev, "rlswitchphydump\n"); 392165782Sticso for (phy = 0; phy <= 5; phy++) { 393165782Sticso printf("PHY%i:", phy); 394165782Sticso for (reg = 0; reg <= 31; reg++) { 395165782Sticso val = MIIBUS_READREG(sc->mii_dev, phy, reg); 396165782Sticso printf(" 0x%x", val); 397165782Sticso } 398165782Sticso printf("\n"); 399165782Sticso } 400165782Sticso} 401165782Sticso#endif 402