1 /*- 2 * Copyright (c) 1997, 1998, 1999 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * Copyright (c) 2006 Bernd Walter. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Bill Paul. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 /* 38 * driver for RealTek 8305 pseudo PHYs 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/module.h> 45 #include <sys/socket.h> 46 #include <sys/bus.h> 47 #include <sys/taskqueue.h> /* XXXGL: if_rlreg.h contamination */ 48 49 #include <net/if.h> 50 #include <net/if_arp.h> 51 #include <net/if_media.h> 52 53 #include <dev/mii/mii.h> 54 #include <dev/mii/miivar.h> 55 #include "miidevs.h" 56 57 #include <machine/bus.h> 58 #include <pci/if_rlreg.h> 59 60 #include "miibus_if.h" 61 62 //#define RL_DEBUG 63 #define RL_VLAN 64 65 static int rlswitch_probe(device_t); 66 static int rlswitch_attach(device_t); 67 68 static device_method_t rlswitch_methods[] = { 69 /* device interface */ 70 DEVMETHOD(device_probe, rlswitch_probe), 71 DEVMETHOD(device_attach, rlswitch_attach), 72 DEVMETHOD(device_detach, mii_phy_detach), 73 DEVMETHOD(device_shutdown, bus_generic_shutdown), 74 DEVMETHOD_END 75 }; 76 77 static devclass_t rlswitch_devclass; 78 79 static driver_t rlswitch_driver = { 80 "rlswitch", 81 rlswitch_methods, 82 sizeof(struct mii_softc) 83 }; 84 85 DRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0); 86 87 static int rlswitch_service(struct mii_softc *, struct mii_data *, int); 88 static void rlswitch_status(struct mii_softc *); 89 90 #ifdef RL_DEBUG 91 static void rlswitch_phydump(device_t dev); 92 #endif 93 94 static const struct mii_phydesc rlswitches[] = { 95 MII_PHY_DESC(REALTEK, RTL8305SC), 96 MII_PHY_END 97 }; 98 99 static const struct mii_phy_funcs rlswitch_funcs = { 100 rlswitch_service, 101 rlswitch_status, 102 mii_phy_reset 103 }; 104 105 static int 106 rlswitch_probe(device_t dev) 107 { 108 int rv; 109 110 rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); 111 if (rv <= 0) 112 return (rv); 113 114 return (ENXIO); 115 } 116 117 static int 118 rlswitch_attach(device_t dev) 119 { 120 struct mii_softc *sc; 121 122 sc = device_get_softc(dev); 123 124 /* 125 * We handle all pseudo PHYs in a single instance. 126 */ 127 mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 128 &rlswitch_funcs, 0); 129 130 sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask; 131 device_printf(dev, " "); 132 mii_phy_add_media(sc); 133 printf("\n"); 134 #ifdef RL_DEBUG 135 rlswitch_phydump(dev); 136 #endif 137 138 #ifdef RL_VLAN 139 int val; 140 141 /* Global Control 0 */ 142 val = 0; 143 val |= 0 << 10; /* enable 802.1q VLAN Tag support */ 144 val |= 0 << 9; /* enable VLAN ingress filtering */ 145 val |= 1 << 8; /* disable VLAN tag admit control */ 146 val |= 1 << 6; /* internal use */ 147 val |= 1 << 5; /* internal use */ 148 val |= 1 << 4; /* internal use */ 149 val |= 1 << 3; /* internal use */ 150 val |= 1 << 1; /* reserved */ 151 MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); 152 153 /* Global Control 2 */ 154 val = 0; 155 val |= 1 << 15; /* reserved */ 156 val |= 0 << 14; /* enable 1552 Bytes support */ 157 val |= 1 << 13; /* enable broadcast input drop */ 158 val |= 1 << 12; /* forward reserved control frames */ 159 val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ 160 val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ 161 val |= 1 << 9; /* enable 48 pass 1 */ 162 val |= 0 << 8; /* enable VLAN */ 163 val |= 1 << 7; /* reserved */ 164 val |= 1 << 6; /* enable defer */ 165 val |= 1 << 5; /* 43ms LED blink time */ 166 val |= 3 << 3; /* 16:1 queue weight */ 167 val |= 1 << 2; /* disable broadcast storm control */ 168 val |= 1 << 1; /* enable power-on LED blinking */ 169 val |= 1 << 0; /* reserved */ 170 MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); 171 172 /* Port 0 Control Register 0 */ 173 val = 0; 174 val |= 1 << 15; /* reserved */ 175 val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 176 val |= 1 << 10; /* disable 802.1p priority classification */ 177 val |= 1 << 9; /* disable diffserv priority classification */ 178 val |= 1 << 6; /* internal use */ 179 val |= 3 << 4; /* internal use */ 180 val |= 1 << 3; /* internal use */ 181 val |= 1 << 2; /* internal use */ 182 val |= 1 << 0; /* remove VLAN tags on output */ 183 MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); 184 185 /* Port 1 Control Register 0 */ 186 val = 0; 187 val |= 1 << 15; /* reserved */ 188 val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 189 val |= 1 << 10; /* disable 802.1p priority classification */ 190 val |= 1 << 9; /* disable diffserv priority classification */ 191 val |= 1 << 6; /* internal use */ 192 val |= 3 << 4; /* internal use */ 193 val |= 1 << 3; /* internal use */ 194 val |= 1 << 2; /* internal use */ 195 val |= 1 << 0; /* remove VLAN tags on output */ 196 MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); 197 198 /* Port 2 Control Register 0 */ 199 val = 0; 200 val |= 1 << 15; /* reserved */ 201 val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 202 val |= 1 << 10; /* disable 802.1p priority classification */ 203 val |= 1 << 9; /* disable diffserv priority classification */ 204 val |= 1 << 6; /* internal use */ 205 val |= 3 << 4; /* internal use */ 206 val |= 1 << 3; /* internal use */ 207 val |= 1 << 2; /* internal use */ 208 val |= 1 << 0; /* remove VLAN tags on output */ 209 MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); 210 211 /* Port 3 Control Register 0 */ 212 val = 0; 213 val |= 1 << 15; /* reserved */ 214 val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 215 val |= 1 << 10; /* disable 802.1p priority classification */ 216 val |= 1 << 9; /* disable diffserv priority classification */ 217 val |= 1 << 6; /* internal use */ 218 val |= 3 << 4; /* internal use */ 219 val |= 1 << 3; /* internal use */ 220 val |= 1 << 2; /* internal use */ 221 val |= 1 << 0; /* remove VLAN tags on output */ 222 MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); 223 224 /* Port 4 (system port) Control Register 0 */ 225 val = 0; 226 val |= 1 << 15; /* reserved */ 227 val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ 228 val |= 1 << 10; /* disable 802.1p priority classification */ 229 val |= 1 << 9; /* disable diffserv priority classification */ 230 val |= 1 << 6; /* internal use */ 231 val |= 3 << 4; /* internal use */ 232 val |= 1 << 3; /* internal use */ 233 val |= 1 << 2; /* internal use */ 234 val |= 2 << 0; /* add VLAN tags for untagged packets on output */ 235 MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); 236 237 /* Port 0 Control Register 1 and VLAN A */ 238 val = 0; 239 val |= 0x0 << 12; /* Port 0 VLAN Index */ 240 val |= 1 << 11; /* internal use */ 241 val |= 1 << 10; /* internal use */ 242 val |= 1 << 9; /* internal use */ 243 val |= 1 << 7; /* internal use */ 244 val |= 1 << 6; /* internal use */ 245 val |= 0x11 << 0; /* VLAN A membership */ 246 MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); 247 248 /* Port 0 Control Register 2 and VLAN A */ 249 val = 0; 250 val |= 1 << 15; /* internal use */ 251 val |= 1 << 14; /* internal use */ 252 val |= 1 << 13; /* internal use */ 253 val |= 1 << 12; /* internal use */ 254 val |= 0x100 << 0; /* VLAN A ID */ 255 MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); 256 257 /* Port 1 Control Register 1 and VLAN B */ 258 val = 0; 259 val |= 0x1 << 12; /* Port 1 VLAN Index */ 260 val |= 1 << 11; /* internal use */ 261 val |= 1 << 10; /* internal use */ 262 val |= 1 << 9; /* internal use */ 263 val |= 1 << 7; /* internal use */ 264 val |= 1 << 6; /* internal use */ 265 val |= 0x12 << 0; /* VLAN B membership */ 266 MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); 267 268 /* Port 1 Control Register 2 and VLAN B */ 269 val = 0; 270 val |= 1 << 15; /* internal use */ 271 val |= 1 << 14; /* internal use */ 272 val |= 1 << 13; /* internal use */ 273 val |= 1 << 12; /* internal use */ 274 val |= 0x101 << 0; /* VLAN B ID */ 275 MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); 276 277 /* Port 2 Control Register 1 and VLAN C */ 278 val = 0; 279 val |= 0x2 << 12; /* Port 2 VLAN Index */ 280 val |= 1 << 11; /* internal use */ 281 val |= 1 << 10; /* internal use */ 282 val |= 1 << 9; /* internal use */ 283 val |= 1 << 7; /* internal use */ 284 val |= 1 << 6; /* internal use */ 285 val |= 0x14 << 0; /* VLAN C membership */ 286 MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); 287 288 /* Port 2 Control Register 2 and VLAN C */ 289 val = 0; 290 val |= 1 << 15; /* internal use */ 291 val |= 1 << 14; /* internal use */ 292 val |= 1 << 13; /* internal use */ 293 val |= 1 << 12; /* internal use */ 294 val |= 0x102 << 0; /* VLAN C ID */ 295 MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); 296 297 /* Port 3 Control Register 1 and VLAN D */ 298 val = 0; 299 val |= 0x3 << 12; /* Port 3 VLAN Index */ 300 val |= 1 << 11; /* internal use */ 301 val |= 1 << 10; /* internal use */ 302 val |= 1 << 9; /* internal use */ 303 val |= 1 << 7; /* internal use */ 304 val |= 1 << 6; /* internal use */ 305 val |= 0x18 << 0; /* VLAN D membership */ 306 MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); 307 308 /* Port 3 Control Register 2 and VLAN D */ 309 val = 0; 310 val |= 1 << 15; /* internal use */ 311 val |= 1 << 14; /* internal use */ 312 val |= 1 << 13; /* internal use */ 313 val |= 1 << 12; /* internal use */ 314 val |= 0x103 << 0; /* VLAN D ID */ 315 MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); 316 317 /* Port 4 Control Register 1 and VLAN E */ 318 val = 0; 319 val |= 0x0 << 12; /* Port 4 VLAN Index */ 320 val |= 1 << 11; /* internal use */ 321 val |= 1 << 10; /* internal use */ 322 val |= 1 << 9; /* internal use */ 323 val |= 1 << 7; /* internal use */ 324 val |= 1 << 6; /* internal use */ 325 val |= 0 << 0; /* VLAN E membership */ 326 MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); 327 328 /* Port 4 Control Register 2 and VLAN E */ 329 val = 0; 330 val |= 1 << 15; /* internal use */ 331 val |= 1 << 14; /* internal use */ 332 val |= 1 << 13; /* internal use */ 333 val |= 1 << 12; /* internal use */ 334 val |= 0x104 << 0; /* VLAN E ID */ 335 MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); 336 #endif 337 338 #ifdef RL_DEBUG 339 rlswitch_phydump(dev); 340 #endif 341 MIIBUS_MEDIAINIT(sc->mii_dev); 342 return (0); 343 } 344 345 static int 346 rlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 347 { 348 349 switch (cmd) { 350 case MII_POLLSTAT: 351 break; 352 353 case MII_MEDIACHG: 354 break; 355 356 case MII_TICK: 357 break; 358 } 359 360 /* Update the media status. */ 361 PHY_STATUS(sc); 362 363 /* Callback if something changed. */ 364 // mii_phy_update(sc, cmd); 365 return (0); 366 } 367 368 static void 369 rlswitch_status(struct mii_softc *phy) 370 { 371 struct mii_data *mii = phy->mii_pdata; 372 373 mii->mii_media_status = IFM_AVALID; 374 mii->mii_media_active = IFM_ETHER; 375 mii->mii_media_status |= IFM_ACTIVE; 376 mii->mii_media_active |= 377 IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy); 378 } 379 380 #ifdef RL_DEBUG 381 static void 382 rlswitch_phydump(device_t dev) { 383 int phy, reg, val; 384 struct mii_softc *sc; 385 386 sc = device_get_softc(dev); 387 device_printf(dev, "rlswitchphydump\n"); 388 for (phy = 0; phy <= 5; phy++) { 389 printf("PHY%i:", phy); 390 for (reg = 0; reg <= 31; reg++) { 391 val = MIIBUS_READREG(sc->mii_dev, phy, reg); 392 printf(" 0x%x", val); 393 } 394 printf("\n"); 395 } 396 } 397 #endif 398