rlswitch.c revision 165782
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 165782 2007-01-05 01:46:26Z ticso $"); 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), 73165782Sticso { 0, 0 } 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[] = { 94165782Sticso MII_PHY_DESC(xxREALTEK, RTL8305SC), 95165782Sticso MII_PHY_END 96165782Sticso}; 97165782Sticso 98165782Sticsostatic int 99165782Sticsorlswitch_probe(device_t dev) 100165782Sticso{ 101165782Sticso int rv; 102165782Sticso 103165782Sticso rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); 104165782Sticso if (rv <= 0) 105165782Sticso return (rv); 106165782Sticso 107165782Sticso return (ENXIO); 108165782Sticso} 109165782Sticso 110165782Sticsostatic int 111165782Sticsorlswitch_attach(device_t dev) 112165782Sticso{ 113165782Sticso struct mii_softc *sc; 114165782Sticso struct mii_attach_args *ma; 115165782Sticso struct mii_data *mii; 116165782Sticso 117165782Sticso sc = device_get_softc(dev); 118165782Sticso ma = device_get_ivars(dev); 119165782Sticso sc->mii_dev = device_get_parent(dev); 120165782Sticso mii = device_get_softc(sc->mii_dev); 121165782Sticso 122165782Sticso /* 123165782Sticso * We handle all pseudo PHY in a single instance, so never allow 124165782Sticso * non-zero * instances! 125165782Sticso */ 126165782Sticso if (mii->mii_instance != 0) { 127165782Sticso device_printf(dev, "ignoring this PHY, non-zero instance\n"); 128165782Sticso return (ENXIO); 129165782Sticso } 130165782Sticso 131165782Sticso LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); 132165782Sticso 133165782Sticso sc->mii_inst = mii->mii_instance; 134165782Sticso sc->mii_phy = ma->mii_phyno; 135165782Sticso sc->mii_service = rlswitch_service; 136165782Sticso sc->mii_pdata = mii; 137165782Sticso mii->mii_instance++; 138165782Sticso 139165782Sticso sc->mii_flags |= MIIF_NOISOLATE; 140165782Sticso 141165782Sticso#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 142165782Sticso 143165782Sticso#if 0 /* See above. */ 144165782Sticso ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 145165782Sticso BMCR_ISO); 146165782Sticso#endif 147165782Sticso 148165782Sticso#if 0 149165782Sticso ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), 150165782Sticso BMCR_LOOP|BMCR_S100); 151165782Sticso#endif 152165782Sticso 153165782Sticso sc->mii_capabilities = BMSR_100TXFDX & ma->mii_capmask; 154165782Sticso device_printf(dev, " "); 155165782Sticso mii_phy_add_media(sc); 156165782Sticso printf("\n"); 157165782Sticso#undef ADD 158165782Sticso#ifdef RL_DEBUG 159165782Sticso rlswitch_phydump(dev); 160165782Sticso#endif 161165782Sticso 162165782Sticso#ifdef RL_VLAN 163165782Sticso int val; 164165782Sticso 165165782Sticso /* Global Control 0 */ 166165782Sticso val = 0; 167165782Sticso val |= 0 << 10; /* enable 802.1q VLAN Tag support */ 168165782Sticso val |= 0 << 9; /* enable VLAN ingress filtering */ 169165782Sticso val |= 1 << 8; /* disable VLAN tag admit control */ 170165782Sticso val |= 1 << 6; /* internal use */ 171165782Sticso val |= 1 << 5; /* internal use */ 172165782Sticso val |= 1 << 4; /* internal use */ 173165782Sticso val |= 1 << 3; /* internal use */ 174165782Sticso val |= 1 << 1; /* reserved */ 175165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); 176165782Sticso 177165782Sticso /* Global Control 2 */ 178165782Sticso val = 0; 179165782Sticso val |= 1 << 15; /* reserved */ 180165782Sticso val |= 0 << 14; /* enable 1552 Bytes support */ 181165782Sticso val |= 1 << 13; /* enable broadcast input drop */ 182165782Sticso val |= 1 << 12; /* forward reserved control frames */ 183165782Sticso val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ 184165782Sticso val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ 185165782Sticso val |= 1 << 9; /* enable 48 pass 1 */ 186165782Sticso val |= 0 << 8; /* enable VLAN */ 187165782Sticso val |= 1 << 7; /* reserved */ 188165782Sticso val |= 1 << 6; /* enable defer */ 189165782Sticso val |= 1 << 5; /* 43ms LED blink time */ 190165782Sticso val |= 3 << 3; /* 16:1 queue weight */ 191165782Sticso val |= 1 << 2; /* disable broadcast storm control */ 192165782Sticso val |= 1 << 1; /* enable power-on LED blinking */ 193165782Sticso val |= 1 << 0; /* reserved */ 194165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); 195165782Sticso 196165782Sticso /* Port 0 Control Register 0 */ 197165782Sticso val = 0; 198165782Sticso val |= 1 << 15; /* reserved */ 199165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 200165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 201165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 202165782Sticso val |= 1 << 6; /* internal use */ 203165782Sticso val |= 3 << 4; /* internal use */ 204165782Sticso val |= 1 << 3; /* internal use */ 205165782Sticso val |= 1 << 2; /* internal use */ 206165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 207165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); 208165782Sticso 209165782Sticso /* Port 1 Control Register 0 */ 210165782Sticso val = 0; 211165782Sticso val |= 1 << 15; /* reserved */ 212165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 213165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 214165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 215165782Sticso val |= 1 << 6; /* internal use */ 216165782Sticso val |= 3 << 4; /* internal use */ 217165782Sticso val |= 1 << 3; /* internal use */ 218165782Sticso val |= 1 << 2; /* internal use */ 219165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 220165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); 221165782Sticso 222165782Sticso /* Port 2 Control Register 0 */ 223165782Sticso val = 0; 224165782Sticso val |= 1 << 15; /* reserved */ 225165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 226165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 227165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 228165782Sticso val |= 1 << 6; /* internal use */ 229165782Sticso val |= 3 << 4; /* internal use */ 230165782Sticso val |= 1 << 3; /* internal use */ 231165782Sticso val |= 1 << 2; /* internal use */ 232165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 233165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); 234165782Sticso 235165782Sticso /* Port 3 Control Register 0 */ 236165782Sticso val = 0; 237165782Sticso val |= 1 << 15; /* reserved */ 238165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 239165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 240165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 241165782Sticso val |= 1 << 6; /* internal use */ 242165782Sticso val |= 3 << 4; /* internal use */ 243165782Sticso val |= 1 << 3; /* internal use */ 244165782Sticso val |= 1 << 2; /* internal use */ 245165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 246165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); 247165782Sticso 248165782Sticso /* Port 4 (system port) Control Register 0 */ 249165782Sticso val = 0; 250165782Sticso val |= 1 << 15; /* reserved */ 251165782Sticso val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ 252165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 253165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 254165782Sticso val |= 1 << 6; /* internal use */ 255165782Sticso val |= 3 << 4; /* internal use */ 256165782Sticso val |= 1 << 3; /* internal use */ 257165782Sticso val |= 1 << 2; /* internal use */ 258165782Sticso val |= 2 << 0; /* add VLAN tags for untagged packets on output */ 259165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); 260165782Sticso 261165782Sticso /* Port 0 Control Register 1 and VLAN A */ 262165782Sticso val = 0; 263165782Sticso val |= 0x0 << 12; /* Port 0 VLAN Index */ 264165782Sticso val |= 1 << 11; /* internal use */ 265165782Sticso val |= 1 << 10; /* internal use */ 266165782Sticso val |= 1 << 9; /* internal use */ 267165782Sticso val |= 1 << 7; /* internal use */ 268165782Sticso val |= 1 << 6; /* internal use */ 269165782Sticso val |= 0x11 << 0; /* VLAN A membership */ 270165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); 271165782Sticso 272165782Sticso /* Port 0 Control Register 2 and VLAN A */ 273165782Sticso val = 0; 274165782Sticso val |= 1 << 15; /* internal use */ 275165782Sticso val |= 1 << 14; /* internal use */ 276165782Sticso val |= 1 << 13; /* internal use */ 277165782Sticso val |= 1 << 12; /* internal use */ 278165782Sticso val |= 0x100 << 0; /* VLAN A ID */ 279165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); 280165782Sticso 281165782Sticso /* Port 1 Control Register 1 and VLAN B */ 282165782Sticso val = 0; 283165782Sticso val |= 0x1 << 12; /* Port 1 VLAN Index */ 284165782Sticso val |= 1 << 11; /* internal use */ 285165782Sticso val |= 1 << 10; /* internal use */ 286165782Sticso val |= 1 << 9; /* internal use */ 287165782Sticso val |= 1 << 7; /* internal use */ 288165782Sticso val |= 1 << 6; /* internal use */ 289165782Sticso val |= 0x12 << 0; /* VLAN B membership */ 290165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); 291165782Sticso 292165782Sticso /* Port 1 Control Register 2 and VLAN B */ 293165782Sticso val = 0; 294165782Sticso val |= 1 << 15; /* internal use */ 295165782Sticso val |= 1 << 14; /* internal use */ 296165782Sticso val |= 1 << 13; /* internal use */ 297165782Sticso val |= 1 << 12; /* internal use */ 298165782Sticso val |= 0x101 << 0; /* VLAN B ID */ 299165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); 300165782Sticso 301165782Sticso /* Port 2 Control Register 1 and VLAN C */ 302165782Sticso val = 0; 303165782Sticso val |= 0x2 << 12; /* Port 2 VLAN Index */ 304165782Sticso val |= 1 << 11; /* internal use */ 305165782Sticso val |= 1 << 10; /* internal use */ 306165782Sticso val |= 1 << 9; /* internal use */ 307165782Sticso val |= 1 << 7; /* internal use */ 308165782Sticso val |= 1 << 6; /* internal use */ 309165782Sticso val |= 0x14 << 0; /* VLAN C membership */ 310165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); 311165782Sticso 312165782Sticso /* Port 2 Control Register 2 and VLAN C */ 313165782Sticso val = 0; 314165782Sticso val |= 1 << 15; /* internal use */ 315165782Sticso val |= 1 << 14; /* internal use */ 316165782Sticso val |= 1 << 13; /* internal use */ 317165782Sticso val |= 1 << 12; /* internal use */ 318165782Sticso val |= 0x102 << 0; /* VLAN C ID */ 319165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); 320165782Sticso 321165782Sticso /* Port 3 Control Register 1 and VLAN D */ 322165782Sticso val = 0; 323165782Sticso val |= 0x3 << 12; /* Port 3 VLAN Index */ 324165782Sticso val |= 1 << 11; /* internal use */ 325165782Sticso val |= 1 << 10; /* internal use */ 326165782Sticso val |= 1 << 9; /* internal use */ 327165782Sticso val |= 1 << 7; /* internal use */ 328165782Sticso val |= 1 << 6; /* internal use */ 329165782Sticso val |= 0x18 << 0; /* VLAN D membership */ 330165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); 331165782Sticso 332165782Sticso /* Port 3 Control Register 2 and VLAN D */ 333165782Sticso val = 0; 334165782Sticso val |= 1 << 15; /* internal use */ 335165782Sticso val |= 1 << 14; /* internal use */ 336165782Sticso val |= 1 << 13; /* internal use */ 337165782Sticso val |= 1 << 12; /* internal use */ 338165782Sticso val |= 0x103 << 0; /* VLAN D ID */ 339165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); 340165782Sticso 341165782Sticso /* Port 4 Control Register 1 and VLAN E */ 342165782Sticso val = 0; 343165782Sticso val |= 0x0 << 12; /* Port 4 VLAN Index */ 344165782Sticso val |= 1 << 11; /* internal use */ 345165782Sticso val |= 1 << 10; /* internal use */ 346165782Sticso val |= 1 << 9; /* internal use */ 347165782Sticso val |= 1 << 7; /* internal use */ 348165782Sticso val |= 1 << 6; /* internal use */ 349165782Sticso val |= 0 << 0; /* VLAN E membership */ 350165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); 351165782Sticso 352165782Sticso /* Port 4 Control Register 2 and VLAN E */ 353165782Sticso val = 0; 354165782Sticso val |= 1 << 15; /* internal use */ 355165782Sticso val |= 1 << 14; /* internal use */ 356165782Sticso val |= 1 << 13; /* internal use */ 357165782Sticso val |= 1 << 12; /* internal use */ 358165782Sticso val |= 0x104 << 0; /* VLAN E ID */ 359165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); 360165782Sticso#endif 361165782Sticso 362165782Sticso#ifdef RL_DEBUG 363165782Sticso rlswitch_phydump(dev); 364165782Sticso#endif 365165782Sticso MIIBUS_MEDIAINIT(sc->mii_dev); 366165782Sticso return (0); 367165782Sticso} 368165782Sticso 369165782Sticsostatic int 370165782Sticsorlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 371165782Sticso{ 372165782Sticso 373165782Sticso switch (cmd) { 374165782Sticso case MII_POLLSTAT: 375165782Sticso break; 376165782Sticso 377165782Sticso case MII_MEDIACHG: 378165782Sticso break; 379165782Sticso 380165782Sticso case MII_TICK: 381165782Sticso /* 382165782Sticso * Is the interface even up? 383165782Sticso */ 384165782Sticso if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 385165782Sticso return (0); 386165782Sticso break; 387165782Sticso } 388165782Sticso 389165782Sticso /* Update the media status. */ 390165782Sticso rlswitch_status(sc); 391165782Sticso 392165782Sticso /* Callback if something changed. */ 393165782Sticso // mii_phy_update(sc, cmd); 394165782Sticso return (0); 395165782Sticso} 396165782Sticso 397165782Sticsostatic void 398165782Sticsorlswitch_status(struct mii_softc *phy) 399165782Sticso{ 400165782Sticso struct mii_data *mii = phy->mii_pdata; 401165782Sticso 402165782Sticso mii->mii_media_status = IFM_AVALID; 403165782Sticso mii->mii_media_active = IFM_ETHER; 404165782Sticso mii->mii_media_status |= IFM_ACTIVE; 405165782Sticso mii->mii_media_active |= IFM_100_TX|IFM_FDX; 406165782Sticso} 407165782Sticso 408165782Sticso#ifdef RL_DEBUG 409165782Sticsostatic void 410165782Sticsorlswitch_phydump(device_t dev) { 411165782Sticso int phy, reg, val; 412165782Sticso struct mii_softc *sc; 413165782Sticso 414165782Sticso sc = device_get_softc(dev); 415165782Sticso device_printf(dev, "rlswitchphydump\n"); 416165782Sticso for (phy = 0; phy <= 5; phy++) { 417165782Sticso printf("PHY%i:", phy); 418165782Sticso for (reg = 0; reg <= 31; reg++) { 419165782Sticso val = MIIBUS_READREG(sc->mii_dev, phy, reg); 420165782Sticso printf(" 0x%x", val); 421165782Sticso } 422165782Sticso printf("\n"); 423165782Sticso } 424165782Sticso} 425165782Sticso#endif 426