1 /*- 2 * Copyright (c) 2016-2017 Hiroki Mori 3 * Copyright (c) 2013 Luiz Otavio O Souza. 4 * Copyright (c) 2011-2012 Stefan Bethke. 5 * Copyright (c) 2012 Adrian Chadd. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * This code is Marvell 88E6060 ethernet switch support code on etherswitch 32 * framework. 33 * 88E6060 support is only port vlan support. Not support ingress/egress 34 * trailer. 35 * 88E6065 support is port and dot1q vlan. Also group base tag support. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/bus.h> 40 #include <sys/errno.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/module.h> 45 #include <sys/mutex.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/sysctl.h> 49 #include <sys/systm.h> 50 51 #include <net/if.h> 52 #include <net/if_var.h> 53 #include <net/ethernet.h> 54 #include <net/if_media.h> 55 #include <net/if_types.h> 56 57 #include <machine/bus.h> 58 #include <dev/mii/mii.h> 59 #include <dev/mii/miivar.h> 60 #include <dev/mdio/mdio.h> 61 62 #include <dev/etherswitch/etherswitch.h> 63 64 #include "mdio_if.h" 65 #include "miibus_if.h" 66 #include "etherswitch_if.h" 67 68 #define CORE_REGISTER 0x8 69 #define SWITCH_ID 3 70 71 #define PORT_CONTROL 4 72 #define ENGRESSFSHIFT 2 73 #define ENGRESSFMASK 3 74 #define ENGRESSTAGSHIFT 12 75 #define ENGRESSTAGMASK 3 76 77 #define PORT_VLAN_MAP 6 78 #define FORCEMAPSHIFT 8 79 #define FORCEMAPMASK 1 80 81 #define PORT_DEFVLAN 7 82 #define DEFVIDMASK 0xfff 83 #define DEFPRIMASK 7 84 85 #define PORT_CONTROL2 8 86 #define DOT1QMODESHIFT 10 87 #define DOT1QMODEMASK 3 88 #define DOT1QNONE 0 89 #define DOT1QFALLBACK 1 90 #define DOT1QCHECK 2 91 #define DOT1QSECURE 3 92 93 #define GLOBAL_REGISTER 0xf 94 95 #define VTU_OPERATION 5 96 #define VTU_VID_REG 6 97 #define VTU_DATA1_REG 7 98 #define VTU_DATA2_REG 8 99 #define VTU_DATA3_REG 9 100 #define VTU_BUSY 0x8000 101 #define VTU_FLASH 1 102 #define VTU_LOAD_PURGE 3 103 #define VTU_GET_NEXT 4 104 #define VTU_VIOLATION 7 105 106 MALLOC_DECLARE(M_E6060SW); 107 MALLOC_DEFINE(M_E6060SW, "e6060sw", "e6060sw data structures"); 108 109 struct e6060sw_softc { 110 struct mtx sc_mtx; /* serialize access to softc */ 111 device_t sc_dev; 112 int vlan_mode; 113 int media; /* cpu port media */ 114 int cpuport; /* which PHY is connected to the CPU */ 115 int phymask; /* PHYs we manage */ 116 int numports; /* number of ports */ 117 int ifpport[MII_NPHY]; 118 int *portphy; 119 char **ifname; 120 device_t **miibus; 121 if_t *ifp; 122 struct callout callout_tick; 123 etherswitch_info_t info; 124 int smi_offset; 125 int sw_model; 126 }; 127 128 /* Switch Identifier DeviceID */ 129 130 #define E6060 0x60 131 #define E6063 0x63 132 #define E6065 0x65 133 134 #define E6060SW_LOCK(_sc) \ 135 mtx_lock(&(_sc)->sc_mtx) 136 #define E6060SW_UNLOCK(_sc) \ 137 mtx_unlock(&(_sc)->sc_mtx) 138 #define E6060SW_LOCK_ASSERT(_sc, _what) \ 139 mtx_assert(&(_sc)->sc_mtx, (_what)) 140 #define E6060SW_TRYLOCK(_sc) \ 141 mtx_trylock(&(_sc)->sc_mtx) 142 143 #if defined(DEBUG) 144 #define DPRINTF(dev, args...) device_printf(dev, args) 145 #else 146 #define DPRINTF(dev, args...) 147 #endif 148 149 static inline int e6060sw_portforphy(struct e6060sw_softc *, int); 150 static void e6060sw_tick(void *); 151 static int e6060sw_ifmedia_upd(if_t); 152 static void e6060sw_ifmedia_sts(if_t, struct ifmediareq *); 153 154 static void e6060sw_setup(device_t dev); 155 static int e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2); 156 static void e6060sw_set_vtu(device_t dev, int num, int data1, int data2); 157 158 static int 159 e6060sw_probe(device_t dev) 160 { 161 int data; 162 struct e6060sw_softc *sc; 163 int devid, i; 164 char *devname; 165 166 sc = device_get_softc(dev); 167 bzero(sc, sizeof(*sc)); 168 169 devid = 0; 170 for (i = 0; i < 2; ++i) { 171 data = MDIO_READREG(device_get_parent(dev), 172 CORE_REGISTER + i * 0x10, SWITCH_ID); 173 if (bootverbose) 174 device_printf(dev,"Switch Identifier Register %x\n", 175 data); 176 177 devid = data >> 4; 178 if (devid == E6060 || 179 devid == E6063 || devid == E6065) { 180 sc->sw_model = devid; 181 sc->smi_offset = i * 0x10; 182 break; 183 } 184 } 185 186 if (devid == E6060) 187 devname = "88E6060"; 188 else if (devid == E6063) 189 devname = "88E6063"; 190 else if (devid == E6065) 191 devname = "88E6065"; 192 else 193 return (ENXIO); 194 195 device_set_descf(dev, "Marvell %s MDIO switch driver at 0x%02x", 196 devname, sc->smi_offset); 197 198 return (BUS_PROBE_DEFAULT); 199 } 200 201 static int 202 e6060sw_attach_phys(struct e6060sw_softc *sc) 203 { 204 int phy, port, err; 205 char name[IFNAMSIZ]; 206 207 port = 0; 208 err = 0; 209 /* PHYs need an interface, so we generate a dummy one */ 210 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 211 for (phy = 0; phy < sc->numports; phy++) { 212 if (((1 << phy) & sc->phymask) == 0) 213 continue; 214 sc->ifpport[phy] = port; 215 sc->portphy[port] = phy; 216 sc->ifp[port] = if_alloc(IFT_ETHER); 217 sc->ifp[port]->if_softc = sc; 218 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | 219 IFF_DRV_RUNNING | IFF_SIMPLEX; 220 if_initname(sc->ifp[port], name, port); 221 sc->miibus[port] = malloc(sizeof(device_t), M_E6060SW, 222 M_WAITOK | M_ZERO); 223 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 224 e6060sw_ifmedia_upd, e6060sw_ifmedia_sts, \ 225 BMSR_DEFCAPMASK, phy + sc->smi_offset, MII_OFFSET_ANY, 0); 226 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 227 device_get_nameunit(*sc->miibus[port]), 228 sc->ifp[port]->if_xname); 229 if (err != 0) { 230 device_printf(sc->sc_dev, 231 "attaching PHY %d failed\n", 232 phy); 233 break; 234 } 235 ++port; 236 } 237 sc->info.es_nports = port; 238 if (sc->cpuport != -1) { 239 /* assume cpuport is last one */ 240 sc->ifpport[sc->cpuport] = port; 241 sc->portphy[port] = sc->cpuport; 242 ++sc->info.es_nports; 243 } 244 return (err); 245 } 246 247 static int 248 e6060sw_attach(device_t dev) 249 { 250 struct e6060sw_softc *sc; 251 int err; 252 253 sc = device_get_softc(dev); 254 err = 0; 255 256 sc->sc_dev = dev; 257 mtx_init(&sc->sc_mtx, "e6060sw", NULL, MTX_DEF); 258 strlcpy(sc->info.es_name, device_get_desc(dev), 259 sizeof(sc->info.es_name)); 260 261 /* XXX Defaults */ 262 if (sc->sw_model == E6063) { 263 sc->numports = 3; 264 sc->phymask = 0x07; 265 sc->cpuport = 2; 266 } else { 267 sc->numports = 6; 268 sc->phymask = 0x1f; 269 sc->cpuport = 5; 270 } 271 sc->media = 100; 272 273 (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 274 "numports", &sc->numports); 275 (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 276 "phymask", &sc->phymask); 277 (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 278 "cpuport", &sc->cpuport); 279 (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 280 "media", &sc->media); 281 282 if (sc->sw_model == E6060) { 283 sc->info.es_nvlangroups = sc->numports; 284 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT; 285 } else { 286 sc->info.es_nvlangroups = 64; 287 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | 288 ETHERSWITCH_VLAN_DOT1Q; 289 } 290 291 e6060sw_setup(dev); 292 293 sc->ifp = malloc(sizeof(if_t) * sc->numports, M_E6060SW, 294 M_WAITOK | M_ZERO); 295 sc->ifname = malloc(sizeof(char *) * sc->numports, M_E6060SW, 296 M_WAITOK | M_ZERO); 297 sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_E6060SW, 298 M_WAITOK | M_ZERO); 299 sc->portphy = malloc(sizeof(int) * sc->numports, M_E6060SW, 300 M_WAITOK | M_ZERO); 301 302 /* 303 * Attach the PHYs and complete the bus enumeration. 304 */ 305 err = e6060sw_attach_phys(sc); 306 if (err != 0) 307 return (err); 308 309 bus_identify_children(dev); 310 bus_enumerate_hinted_children(dev); 311 bus_attach_children(dev); 312 313 callout_init(&sc->callout_tick, 0); 314 315 e6060sw_tick(sc); 316 317 return (err); 318 } 319 320 static int 321 e6060sw_detach(device_t dev) 322 { 323 struct e6060sw_softc *sc; 324 int i, port; 325 326 sc = device_get_softc(dev); 327 328 callout_drain(&sc->callout_tick); 329 330 for (i = 0; i < MII_NPHY; i++) { 331 if (((1 << i) & sc->phymask) == 0) 332 continue; 333 port = e6060sw_portforphy(sc, i); 334 if (sc->miibus[port] != NULL) 335 device_delete_child(dev, (*sc->miibus[port])); 336 if (sc->ifp[port] != NULL) 337 if_free(sc->ifp[port]); 338 free(sc->ifname[port], M_E6060SW); 339 free(sc->miibus[port], M_E6060SW); 340 } 341 342 free(sc->portphy, M_E6060SW); 343 free(sc->miibus, M_E6060SW); 344 free(sc->ifname, M_E6060SW); 345 free(sc->ifp, M_E6060SW); 346 347 bus_generic_detach(dev); 348 mtx_destroy(&sc->sc_mtx); 349 350 return (0); 351 } 352 353 /* 354 * Convert PHY number to port number. 355 */ 356 static inline int 357 e6060sw_portforphy(struct e6060sw_softc *sc, int phy) 358 { 359 360 return (sc->ifpport[phy]); 361 } 362 363 static inline struct mii_data * 364 e6060sw_miiforport(struct e6060sw_softc *sc, int port) 365 { 366 367 if (port < 0 || port > sc->numports) 368 return (NULL); 369 if (port == sc->cpuport) 370 return (NULL); 371 return (device_get_softc(*sc->miibus[port])); 372 } 373 374 static inline if_t 375 e6060sw_ifpforport(struct e6060sw_softc *sc, int port) 376 { 377 378 if (port < 0 || port > sc->numports) 379 return (NULL); 380 return (sc->ifp[port]); 381 } 382 383 /* 384 * Poll the status for all PHYs. 385 */ 386 static void 387 e6060sw_miipollstat(struct e6060sw_softc *sc) 388 { 389 int i, port; 390 struct mii_data *mii; 391 struct mii_softc *miisc; 392 393 E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED); 394 395 for (i = 0; i < MII_NPHY; i++) { 396 if (((1 << i) & sc->phymask) == 0) 397 continue; 398 port = e6060sw_portforphy(sc, i); 399 if ((*sc->miibus[port]) == NULL) 400 continue; 401 mii = device_get_softc(*sc->miibus[port]); 402 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 403 if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 404 miisc->mii_inst) 405 continue; 406 ukphy_status(miisc); 407 mii_phy_update(miisc, MII_POLLSTAT); 408 } 409 } 410 } 411 412 static void 413 e6060sw_tick(void *arg) 414 { 415 struct e6060sw_softc *sc; 416 417 sc = arg; 418 419 e6060sw_miipollstat(sc); 420 callout_reset(&sc->callout_tick, hz, e6060sw_tick, sc); 421 } 422 423 static void 424 e6060sw_lock(device_t dev) 425 { 426 struct e6060sw_softc *sc; 427 428 sc = device_get_softc(dev); 429 430 E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED); 431 E6060SW_LOCK(sc); 432 } 433 434 static void 435 e6060sw_unlock(device_t dev) 436 { 437 struct e6060sw_softc *sc; 438 439 sc = device_get_softc(dev); 440 441 E6060SW_LOCK_ASSERT(sc, MA_OWNED); 442 E6060SW_UNLOCK(sc); 443 } 444 445 static etherswitch_info_t * 446 e6060sw_getinfo(device_t dev) 447 { 448 struct e6060sw_softc *sc; 449 450 sc = device_get_softc(dev); 451 452 return (&sc->info); 453 } 454 455 static int 456 e6060sw_getport(device_t dev, etherswitch_port_t *p) 457 { 458 struct e6060sw_softc *sc; 459 struct mii_data *mii; 460 struct ifmediareq *ifmr; 461 int err, phy; 462 463 sc = device_get_softc(dev); 464 ifmr = &p->es_ifmr; 465 466 if (p->es_port < 0 || p->es_port >= sc->numports) 467 return (ENXIO); 468 469 p->es_pvid = 0; 470 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 471 p->es_pvid = MDIO_READREG(device_get_parent(dev), 472 CORE_REGISTER + sc->smi_offset + p->es_port, 473 PORT_DEFVLAN) & 0xfff; 474 } 475 476 phy = sc->portphy[p->es_port]; 477 mii = e6060sw_miiforport(sc, p->es_port); 478 if (sc->cpuport != -1 && phy == sc->cpuport) { 479 /* fill in fixed values for CPU port */ 480 p->es_flags |= ETHERSWITCH_PORT_CPU; 481 ifmr->ifm_count = 0; 482 if (sc->media == 100) 483 ifmr->ifm_current = ifmr->ifm_active = 484 IFM_ETHER | IFM_100_TX | IFM_FDX; 485 else 486 ifmr->ifm_current = ifmr->ifm_active = 487 IFM_ETHER | IFM_1000_T | IFM_FDX; 488 ifmr->ifm_mask = 0; 489 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 490 } else if (mii != NULL) { 491 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 492 &mii->mii_media, SIOCGIFMEDIA); 493 if (err) 494 return (err); 495 } else { 496 return (ENXIO); 497 } 498 return (0); 499 } 500 501 static int 502 e6060sw_setport(device_t dev, etherswitch_port_t *p) 503 { 504 struct e6060sw_softc *sc; 505 struct ifmedia *ifm; 506 struct mii_data *mii; 507 if_t ifp; 508 int err; 509 int data; 510 511 sc = device_get_softc(dev); 512 513 if (p->es_port < 0 || p->es_port >= sc->numports) 514 return (ENXIO); 515 516 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 517 data = MDIO_READREG(device_get_parent(dev), 518 CORE_REGISTER + sc->smi_offset + p->es_port, 519 PORT_DEFVLAN); 520 data &= ~0xfff; 521 data |= p->es_pvid; 522 data |= 1 << 12; 523 MDIO_WRITEREG(device_get_parent(dev), 524 CORE_REGISTER + sc->smi_offset + p->es_port, 525 PORT_DEFVLAN, data); 526 } 527 528 if (sc->portphy[p->es_port] == sc->cpuport) 529 return(0); 530 531 mii = e6060sw_miiforport(sc, p->es_port); 532 if (mii == NULL) 533 return (ENXIO); 534 535 ifp = e6060sw_ifpforport(sc, p->es_port); 536 537 ifm = &mii->mii_media; 538 err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA); 539 return (err); 540 } 541 542 static int 543 e6060sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 544 { 545 struct e6060sw_softc *sc; 546 int data1, data2; 547 int vid; 548 int i, tag; 549 550 sc = device_get_softc(dev); 551 552 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 553 vg->es_vid = ETHERSWITCH_VID_VALID; 554 vg->es_vid |= vg->es_vlangroup; 555 data1 = MDIO_READREG(device_get_parent(dev), 556 CORE_REGISTER + sc->smi_offset + vg->es_vlangroup, 557 PORT_VLAN_MAP); 558 vg->es_member_ports = data1 & 0x3f; 559 vg->es_untagged_ports = vg->es_member_ports; 560 vg->es_fid = 0; 561 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 562 if (vg->es_vlangroup == 0) 563 return (0); 564 vid = e6060sw_read_vtu(dev, vg->es_vlangroup, &data1, &data2); 565 if (vid > 0) { 566 vg->es_vid = ETHERSWITCH_VID_VALID; 567 vg->es_vid |= vid; 568 vg->es_member_ports = 0; 569 vg->es_untagged_ports = 0; 570 for (i = 0; i < 4; ++i) { 571 tag = data1 >> (i * 4) & 3; 572 if (tag == 0 || tag == 1) { 573 vg->es_member_ports |= 1 << i; 574 vg->es_untagged_ports |= 1 << i; 575 } else if (tag == 2) { 576 vg->es_member_ports |= 1 << i; 577 } 578 } 579 for (i = 0; i < 2; ++i) { 580 tag = data2 >> (i * 4) & 3; 581 if (tag == 0 || tag == 1) { 582 vg->es_member_ports |= 1 << (i + 4); 583 vg->es_untagged_ports |= 1 << (i + 4); 584 } else if (tag == 2) { 585 vg->es_member_ports |= 1 << (i + 4); 586 } 587 } 588 589 } 590 } else { 591 vg->es_vid = 0; 592 } 593 return (0); 594 } 595 596 static int 597 e6060sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 598 { 599 struct e6060sw_softc *sc; 600 int data1, data2; 601 int i; 602 603 sc = device_get_softc(dev); 604 605 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 606 data1 = MDIO_READREG(device_get_parent(dev), 607 CORE_REGISTER + sc->smi_offset + vg->es_vlangroup, 608 PORT_VLAN_MAP); 609 data1 &= ~0x3f; 610 data1 |= vg->es_member_ports; 611 MDIO_WRITEREG(device_get_parent(dev), 612 CORE_REGISTER + sc->smi_offset + vg->es_vlangroup, 613 PORT_VLAN_MAP, data1); 614 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 615 if (vg->es_vlangroup == 0) 616 return (0); 617 data1 = 0; 618 data2 = 0; 619 for (i = 0; i < 6; ++i) { 620 if (vg->es_member_ports & 621 vg->es_untagged_ports & (1 << i)) { 622 if (i < 4) { 623 data1 |= (0xd << i * 4); 624 } else { 625 data2 |= (0xd << (i - 4) * 4); 626 } 627 } else if (vg->es_member_ports & (1 << i)) { 628 if (i < 4) { 629 data1 |= (0xe << i * 4); 630 } else { 631 data2 |= (0xe << (i - 4) * 4); 632 } 633 } else { 634 if (i < 4) { 635 data1 |= (0x3 << i * 4); 636 } else { 637 data2 |= (0x3 << (i - 4) * 4); 638 } 639 } 640 } 641 e6060sw_set_vtu(dev, vg->es_vlangroup, data1, data2); 642 } 643 return (0); 644 } 645 646 static void 647 e6060sw_reset_vlans(device_t dev) 648 { 649 struct e6060sw_softc *sc; 650 uint32_t ports; 651 int i; 652 int data; 653 654 sc = device_get_softc(dev); 655 656 for (i = 0; i <= sc->numports; i++) { 657 ports = (1 << (sc->numports + 1)) - 1; 658 ports &= ~(1 << i); 659 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 660 data = i << 12; 661 } else if (sc->vlan_mode == 0) { 662 data = 1 << 8; 663 } else { 664 data = 0; 665 } 666 data |= ports; 667 MDIO_WRITEREG(device_get_parent(dev), 668 CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP, data); 669 } 670 } 671 672 static void 673 e6060sw_setup(device_t dev) 674 { 675 struct e6060sw_softc *sc; 676 int i; 677 int data; 678 679 sc = device_get_softc(dev); 680 681 for (i = 0; i <= sc->numports; i++) { 682 if (sc->sw_model == E6063 || sc->sw_model == E6065) { 683 data = MDIO_READREG(device_get_parent(dev), 684 CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP); 685 data &= ~(FORCEMAPMASK << FORCEMAPSHIFT); 686 MDIO_WRITEREG(device_get_parent(dev), 687 CORE_REGISTER + sc->smi_offset + i, 688 PORT_VLAN_MAP, data); 689 690 data = MDIO_READREG(device_get_parent(dev), 691 CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL); 692 data |= 3 << ENGRESSFSHIFT; 693 MDIO_WRITEREG(device_get_parent(dev), 694 CORE_REGISTER + sc->smi_offset + i, 695 PORT_CONTROL, data); 696 } 697 } 698 } 699 700 static void 701 e6060sw_dot1q_mode(device_t dev, int mode) 702 { 703 struct e6060sw_softc *sc; 704 int i; 705 int data; 706 707 sc = device_get_softc(dev); 708 709 for (i = 0; i <= sc->numports; i++) { 710 data = MDIO_READREG(device_get_parent(dev), 711 CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2); 712 data &= ~(DOT1QMODEMASK << DOT1QMODESHIFT); 713 data |= mode << DOT1QMODESHIFT; 714 MDIO_WRITEREG(device_get_parent(dev), 715 CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2, data); 716 717 data = MDIO_READREG(device_get_parent(dev), 718 CORE_REGISTER + sc->smi_offset + i, 719 PORT_DEFVLAN); 720 data &= ~0xfff; 721 data |= 1; 722 MDIO_WRITEREG(device_get_parent(dev), 723 CORE_REGISTER + sc->smi_offset + i, 724 PORT_DEFVLAN, data); 725 } 726 } 727 728 static int 729 e6060sw_getconf(device_t dev, etherswitch_conf_t *conf) 730 { 731 struct e6060sw_softc *sc; 732 733 sc = device_get_softc(dev); 734 735 /* Return the VLAN mode. */ 736 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 737 conf->vlan_mode = sc->vlan_mode; 738 739 return (0); 740 } 741 742 static void 743 e6060sw_init_vtu(device_t dev) 744 { 745 struct e6060sw_softc *sc; 746 int busy; 747 748 sc = device_get_softc(dev); 749 750 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 751 VTU_OPERATION, VTU_BUSY | (VTU_FLASH << 12)); 752 while (1) { 753 busy = MDIO_READREG(device_get_parent(dev), 754 GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION); 755 if ((busy & VTU_BUSY) == 0) 756 break; 757 } 758 759 /* initial member set at vlan 1*/ 760 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 761 VTU_DATA1_REG, 0xcccc); 762 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 763 VTU_DATA2_REG, 0x00cc); 764 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 765 VTU_VID_REG, 0x1000 | 1); 766 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 767 VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | 1); 768 while (1) { 769 busy = MDIO_READREG(device_get_parent(dev), 770 GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION); 771 if ((busy & VTU_BUSY) == 0) 772 break; 773 } 774 } 775 776 static void 777 e6060sw_set_vtu(device_t dev, int num, int data1, int data2) 778 { 779 struct e6060sw_softc *sc; 780 int busy; 781 782 sc = device_get_softc(dev); 783 784 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 785 VTU_DATA1_REG, data1); 786 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 787 VTU_DATA2_REG, data2); 788 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 789 VTU_VID_REG, 0x1000 | num); 790 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 791 VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | num); 792 while (1) { 793 busy = MDIO_READREG(device_get_parent(dev), 794 GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION); 795 if ((busy & VTU_BUSY) == 0) 796 break; 797 } 798 799 } 800 801 static int 802 e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2) 803 { 804 struct e6060sw_softc *sc; 805 int busy; 806 807 sc = device_get_softc(dev); 808 809 num = num - 1; 810 811 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 812 VTU_VID_REG, num & 0xfff); 813 /* Get Next */ 814 MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset, 815 VTU_OPERATION, VTU_BUSY | (VTU_GET_NEXT << 12)); 816 while (1) { 817 busy = MDIO_READREG(device_get_parent(dev), 818 GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION); 819 if ((busy & VTU_BUSY) == 0) 820 break; 821 } 822 823 int vid = MDIO_READREG(device_get_parent(dev), 824 GLOBAL_REGISTER + sc->smi_offset, VTU_VID_REG); 825 if (vid & 0x1000) { 826 *data1 = MDIO_READREG(device_get_parent(dev), 827 GLOBAL_REGISTER + sc->smi_offset, VTU_DATA1_REG); 828 *data2 = MDIO_READREG(device_get_parent(dev), 829 GLOBAL_REGISTER + sc->smi_offset, VTU_DATA2_REG); 830 831 return (vid & 0xfff); 832 } 833 834 return (-1); 835 } 836 837 static int 838 e6060sw_setconf(device_t dev, etherswitch_conf_t *conf) 839 { 840 struct e6060sw_softc *sc; 841 842 sc = device_get_softc(dev); 843 844 /* Set the VLAN mode. */ 845 if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) { 846 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) { 847 sc->vlan_mode = ETHERSWITCH_VLAN_PORT; 848 e6060sw_dot1q_mode(dev, DOT1QNONE); 849 e6060sw_reset_vlans(dev); 850 } else if ((sc->sw_model == E6063 || sc->sw_model == E6065) && 851 conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 852 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 853 e6060sw_dot1q_mode(dev, DOT1QSECURE); 854 e6060sw_init_vtu(dev); 855 } else { 856 sc->vlan_mode = 0; 857 /* Reset VLANs. */ 858 e6060sw_dot1q_mode(dev, DOT1QNONE); 859 e6060sw_reset_vlans(dev); 860 } 861 } 862 863 return (0); 864 } 865 866 static void 867 e6060sw_statchg(device_t dev) 868 { 869 870 DPRINTF(dev, "%s\n", __func__); 871 } 872 873 static int 874 e6060sw_ifmedia_upd(if_t ifp) 875 { 876 struct e6060sw_softc *sc; 877 struct mii_data *mii; 878 879 sc = if_getsoftc(ifp); 880 mii = e6060sw_miiforport(sc, if_getdunit(ifp)); 881 882 DPRINTF(sc->sc_dev, "%s\n", __func__); 883 if (mii == NULL) 884 return (ENXIO); 885 mii_mediachg(mii); 886 return (0); 887 } 888 889 static void 890 e6060sw_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 891 { 892 struct e6060sw_softc *sc; 893 struct mii_data *mii; 894 895 sc = if_getsoftc(ifp); 896 mii = e6060sw_miiforport(sc, if_getdunit(ifp)); 897 898 DPRINTF(sc->sc_dev, "%s\n", __func__); 899 900 if (mii == NULL) 901 return; 902 mii_pollstat(mii); 903 ifmr->ifm_active = mii->mii_media_active; 904 ifmr->ifm_status = mii->mii_media_status; 905 } 906 907 static int 908 e6060sw_readphy(device_t dev, int phy, int reg) 909 { 910 struct e6060sw_softc *sc; 911 int data; 912 913 sc = device_get_softc(dev); 914 E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED); 915 916 if (phy < 0 || phy >= 32) 917 return (ENXIO); 918 if (reg < 0 || reg >= 32) 919 return (ENXIO); 920 921 E6060SW_LOCK(sc); 922 data = MDIO_READREG(device_get_parent(dev), phy, reg); 923 E6060SW_UNLOCK(sc); 924 925 return (data); 926 } 927 928 static int 929 e6060sw_writephy(device_t dev, int phy, int reg, int data) 930 { 931 struct e6060sw_softc *sc; 932 int err; 933 934 sc = device_get_softc(dev); 935 E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED); 936 937 if (phy < 0 || phy >= 32) 938 return (ENXIO); 939 if (reg < 0 || reg >= 32) 940 return (ENXIO); 941 942 E6060SW_LOCK(sc); 943 err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data); 944 E6060SW_UNLOCK(sc); 945 946 return (err); 947 } 948 949 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */ 950 951 static int 952 e6060sw_readreg(device_t dev, int addr) 953 { 954 int devaddr, regaddr; 955 956 devaddr = (addr >> 5) & 0x1f; 957 regaddr = addr & 0x1f; 958 959 return MDIO_READREG(device_get_parent(dev), devaddr, regaddr); 960 } 961 962 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */ 963 964 static int 965 e6060sw_writereg(device_t dev, int addr, int value) 966 { 967 int devaddr, regaddr; 968 969 devaddr = (addr >> 5) & 0x1f; 970 regaddr = addr & 0x1f; 971 972 return (MDIO_WRITEREG(device_get_parent(dev), devaddr, regaddr, value)); 973 } 974 975 static device_method_t e6060sw_methods[] = { 976 /* Device interface */ 977 DEVMETHOD(device_probe, e6060sw_probe), 978 DEVMETHOD(device_attach, e6060sw_attach), 979 DEVMETHOD(device_detach, e6060sw_detach), 980 981 /* bus interface */ 982 DEVMETHOD(bus_add_child, device_add_child_ordered), 983 984 /* MII interface */ 985 DEVMETHOD(miibus_readreg, e6060sw_readphy), 986 DEVMETHOD(miibus_writereg, e6060sw_writephy), 987 DEVMETHOD(miibus_statchg, e6060sw_statchg), 988 989 /* MDIO interface */ 990 DEVMETHOD(mdio_readreg, e6060sw_readphy), 991 DEVMETHOD(mdio_writereg, e6060sw_writephy), 992 993 /* etherswitch interface */ 994 DEVMETHOD(etherswitch_lock, e6060sw_lock), 995 DEVMETHOD(etherswitch_unlock, e6060sw_unlock), 996 DEVMETHOD(etherswitch_getinfo, e6060sw_getinfo), 997 DEVMETHOD(etherswitch_readreg, e6060sw_readreg), 998 DEVMETHOD(etherswitch_writereg, e6060sw_writereg), 999 DEVMETHOD(etherswitch_readphyreg, e6060sw_readphy), 1000 DEVMETHOD(etherswitch_writephyreg, e6060sw_writephy), 1001 DEVMETHOD(etherswitch_getport, e6060sw_getport), 1002 DEVMETHOD(etherswitch_setport, e6060sw_setport), 1003 DEVMETHOD(etherswitch_getvgroup, e6060sw_getvgroup), 1004 DEVMETHOD(etherswitch_setvgroup, e6060sw_setvgroup), 1005 DEVMETHOD(etherswitch_setconf, e6060sw_setconf), 1006 DEVMETHOD(etherswitch_getconf, e6060sw_getconf), 1007 1008 DEVMETHOD_END 1009 }; 1010 1011 DEFINE_CLASS_0(e6060sw, e6060sw_driver, e6060sw_methods, 1012 sizeof(struct e6060sw_softc)); 1013 1014 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, 0, 0); 1015 DRIVER_MODULE(miibus, e6060sw, miibus_driver, 0, 0); 1016 DRIVER_MODULE(mdio, e6060sw, mdio_driver, 0, 0); 1017 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, 0, 0); 1018 MODULE_VERSION(e6060sw, 1); 1019 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */ 1020 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */ 1021