1 /*- 2 * Copyright (c) 2015 Semihalf 3 * Copyright (c) 2015 Stormshield 4 * 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/sockio.h> 35 #include <sys/kernel.h> 36 #include <sys/kthread.h> 37 #include <sys/socket.h> 38 #include <sys/module.h> 39 #include <sys/errno.h> 40 #include <sys/bus.h> 41 #include <sys/conf.h> 42 #include <sys/uio.h> 43 #include <sys/fcntl.h> 44 45 #include <net/if.h> 46 #include <net/if_media.h> 47 #include <net/if_types.h> 48 49 #include <machine/bus.h> 50 #include <machine/resource.h> 51 52 #include <arm/mv/mvwin.h> 53 #include <arm/mv/mvreg.h> 54 #include <arm/mv/mvvar.h> 55 56 #include <dev/etherswitch/etherswitch.h> 57 #include <dev/mdio/mdio.h> 58 #include <dev/mii/mii.h> 59 #include <dev/mii/miivar.h> 60 #include <dev/mge/if_mgevar.h> 61 62 #include "e6000swreg.h" 63 #include "etherswitch_if.h" 64 #include "miibus_if.h" 65 #include "mdio_if.h" 66 67 MALLOC_DECLARE(M_E6000SW); 68 MALLOC_DEFINE(M_E6000SW, "e6000sw", "e6000sw switch"); 69 70 #define E6000SW_LOCK(_sc) \ 71 sx_xlock(&(_sc)->sx) 72 #define E6000SW_UNLOCK(_sc) \ 73 sx_unlock(&(_sc)->sx) 74 #define E6000SW_LOCK_ASSERT(_sc, _what) \ 75 sx_assert(&(_sc)->sx, (_what)) 76 #define E6000SW_TRYLOCK(_sc) \ 77 sx_tryxlock(&(_sc)->sx) 78 79 typedef struct e6000sw_softc { 80 device_t dev; 81 82 struct sx sx; 83 struct ifnet *ifp[E6000SW_NUM_PHYS]; 84 char *ifname[E6000SW_NUM_PHYS]; 85 device_t miibus[E6000SW_NUM_PHYS]; 86 struct mii_data *mii[E6000SW_NUM_PHYS]; 87 struct callout tick_callout; 88 89 uint32_t cpuports_mask; 90 91 int vid[E6000SW_NUM_VGROUPS]; 92 int members[E6000SW_NUM_VGROUPS]; 93 int vgroup[E6000SW_NUM_PORTS]; 94 } e6000sw_softc_t; 95 96 static etherswitch_info_t etherswitch_info = { 97 .es_nports = E6000SW_NUM_PORTS, 98 .es_nvlangroups = E6000SW_NUM_VGROUPS, 99 .es_name = "Marvell 6000 series switch" 100 }; 101 102 static void e6000sw_identify(driver_t *driver, device_t parent); 103 static int e6000sw_probe(device_t dev); 104 static int e6000sw_attach(device_t dev); 105 static int e6000sw_detach(device_t dev); 106 static int e6000sw_readphy(device_t dev, int phy, int reg); 107 static int e6000sw_writephy(device_t dev, int phy, int reg, int data); 108 static etherswitch_info_t* e6000sw_getinfo(device_t dev); 109 static void e6000sw_lock(device_t dev); 110 static void e6000sw_unlock(device_t dev); 111 static int e6000sw_getport(device_t dev, etherswitch_port_t *p); 112 static int e6000sw_setport(device_t dev, etherswitch_port_t *p); 113 static int e6000sw_readreg_wrapper(device_t dev, int addr_reg); 114 static int e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val); 115 static int e6000sw_readphy_wrapper(device_t dev, int phy, int reg); 116 static int e6000sw_writephy_wrapper(device_t dev, int phy, int reg, int data); 117 static int e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg); 118 static int e6000sw_setvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg); 119 static int e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg); 120 static int e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg); 121 static void e6000sw_setup(device_t dev, e6000sw_softc_t *sc); 122 static void e6000sw_port_vlan_conf(e6000sw_softc_t *sc); 123 static void e6000sw_tick(void *arg); 124 static void e6000sw_set_atustat(device_t dev, e6000sw_softc_t *sc, int bin, 125 int flag); 126 static int e6000sw_atu_flush(device_t dev, e6000sw_softc_t *sc, int flag); 127 static __inline void e6000sw_writereg(e6000sw_softc_t *sc, int addr, int reg, 128 int val); 129 static __inline uint32_t e6000sw_readreg(e6000sw_softc_t *sc, int addr, 130 int reg); 131 static int e6000sw_ifmedia_upd(struct ifnet *ifp); 132 static void e6000sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 133 static int e6000sw_atu_mac_table(device_t dev, e6000sw_softc_t *sc, struct 134 atu_opt *atu, int flag); 135 static int e6000sw_get_pvid(e6000sw_softc_t *sc, int port, int *pvid); 136 static int e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid); 137 static __inline int e6000sw_cpuport(e6000sw_softc_t *sc, int port); 138 static __inline struct mii_data *e6000sw_miiforphy(e6000sw_softc_t *sc, 139 unsigned int phy); 140 141 static struct proc *e6000sw_kproc; 142 143 static device_method_t e6000sw_methods[] = { 144 /* device interface */ 145 DEVMETHOD(device_identify, e6000sw_identify), 146 DEVMETHOD(device_probe, e6000sw_probe), 147 DEVMETHOD(device_attach, e6000sw_attach), 148 DEVMETHOD(device_detach, e6000sw_detach), 149 150 /* bus interface */ 151 DEVMETHOD(bus_add_child, device_add_child_ordered), 152 153 /* mii interface */ 154 DEVMETHOD(miibus_readreg, e6000sw_readphy), 155 DEVMETHOD(miibus_writereg, e6000sw_writephy), 156 157 /* etherswitch interface */ 158 DEVMETHOD(etherswitch_getinfo, e6000sw_getinfo), 159 DEVMETHOD(etherswitch_lock, e6000sw_lock), 160 DEVMETHOD(etherswitch_unlock, e6000sw_unlock), 161 DEVMETHOD(etherswitch_getport, e6000sw_getport), 162 DEVMETHOD(etherswitch_setport, e6000sw_setport), 163 DEVMETHOD(etherswitch_readreg, e6000sw_readreg_wrapper), 164 DEVMETHOD(etherswitch_writereg, e6000sw_writereg_wrapper), 165 DEVMETHOD(etherswitch_readphyreg, e6000sw_readphy_wrapper), 166 DEVMETHOD(etherswitch_writephyreg, e6000sw_writephy_wrapper), 167 DEVMETHOD(etherswitch_setvgroup, e6000sw_setvgroup_wrapper), 168 DEVMETHOD(etherswitch_getvgroup, e6000sw_getvgroup_wrapper), 169 170 DEVMETHOD_END 171 }; 172 173 static devclass_t e6000sw_devclass; 174 175 DEFINE_CLASS_0(e6000sw, e6000sw_driver, e6000sw_methods, 176 sizeof(e6000sw_softc_t)); 177 178 DRIVER_MODULE(e6000sw, mdio, e6000sw_driver, e6000sw_devclass, 0, 0); 179 DRIVER_MODULE(etherswitch, e6000sw, etherswitch_driver, etherswitch_devclass, 0, 180 0); 181 DRIVER_MODULE(miibus, e6000sw, miibus_driver, miibus_devclass, 0, 0); 182 MODULE_DEPEND(e6000sw, mdio, 1, 1, 1); 183 184 static void 185 e6000sw_identify(driver_t *driver, device_t parent) 186 { 187 188 if (device_find_child(parent, "e6000sw", -1) == NULL) 189 BUS_ADD_CHILD(parent, 0, "e6000sw", -1); 190 } 191 192 static int 193 e6000sw_probe(device_t dev) 194 { 195 e6000sw_softc_t *sc; 196 const char *description; 197 unsigned int id; 198 199 sc = device_get_softc(dev); 200 bzero(sc, sizeof(e6000sw_softc_t)); 201 sc->dev = dev; 202 /* Lock is necessary due to assertions. */ 203 sx_init(&sc->sx, "e6000sw"); 204 E6000SW_LOCK(sc); 205 206 id = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID); 207 208 switch (id & 0xfff0) { 209 case 0x3520: 210 description = "Marvell 88E6352"; 211 break; 212 case 0x1720: 213 description = "Marvell 88E6172"; 214 break; 215 case 0x1760: 216 description = "Marvell 88E6176"; 217 break; 218 default: 219 E6000SW_UNLOCK(sc); 220 sx_destroy(&sc->sx); 221 device_printf(dev, "Unrecognized device.\n"); 222 return (ENXIO); 223 } 224 225 device_set_desc(dev, description); 226 227 E6000SW_UNLOCK(sc); 228 229 return (BUS_PROBE_DEFAULT); 230 } 231 232 static int 233 e6000sw_attach(device_t dev) 234 { 235 e6000sw_softc_t *sc; 236 int phy, err, port; 237 char name[IFNAMSIZ]; 238 239 err = 0; 240 sc = device_get_softc(dev); 241 E6000SW_LOCK(sc); 242 sc->cpuports_mask = E6000SW_CPUPORTS_MASK; 243 for (port = 0; port < E6000SW_NUM_PORTS; port++) 244 sc->vgroup[port] = E6000SW_PORT_NO_VGROUP; 245 e6000sw_setup(dev, sc); 246 247 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->dev)); 248 for (phy = 0; phy < E6000SW_NUM_PHYS; phy++) { 249 sc->ifp[phy] = if_alloc(IFT_ETHER); 250 if (sc->ifp[phy] == NULL) 251 goto out_fail; 252 sc->ifp[phy]->if_softc = sc; 253 sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST | 254 IFF_DRV_RUNNING | IFF_SIMPLEX; 255 sc->ifname[phy] = malloc(strlen(name) + 1, M_E6000SW, M_WAITOK); 256 if (sc->ifname[phy] == NULL) 257 goto out_fail; 258 bcopy(name, sc->ifname[phy], strlen(name) + 1); 259 if_initname(sc->ifp[phy], sc->ifname[phy], phy); 260 err = mii_attach(sc->dev, &sc->miibus[phy], sc->ifp[phy], 261 e6000sw_ifmedia_upd, e6000sw_ifmedia_sts, BMSR_DEFCAPMASK, 262 phy, MII_OFFSET_ANY, 0); 263 if (err != 0) { 264 device_printf(sc->dev, 265 "attaching PHY %d failed\n", 266 phy); 267 goto out_fail; 268 } 269 sc->mii[phy] = device_get_softc(sc->miibus[phy]); 270 } 271 E6000SW_UNLOCK(sc); 272 273 bus_generic_probe(dev); 274 bus_enumerate_hinted_children(dev); 275 bus_generic_attach(dev); 276 277 kproc_create(e6000sw_tick, sc, &e6000sw_kproc, 0, 0, 278 "e6000sw tick kproc"); 279 280 return (0); 281 282 out_fail: 283 e6000sw_detach(dev); 284 285 return (ENXIO); 286 } 287 288 static __inline void 289 e6000sw_poll_done(e6000sw_softc_t *sc) 290 { 291 292 while (e6000sw_readreg(sc, REG_GLOBAL2, PHY_CMD) & 293 (1 << PHY_CMD_SMI_BUSY)) 294 continue; 295 } 296 297 298 /* 299 * PHY registers are paged. Put page index in reg 22 (accessible from every 300 * page), then access specific register. 301 */ 302 static int 303 e6000sw_readphy(device_t dev, int phy, int reg) 304 { 305 e6000sw_softc_t *sc; 306 uint32_t val; 307 308 sc = device_get_softc(dev); 309 val = 0; 310 311 if (phy >= E6000SW_NUM_PHYS || reg >= E6000SW_NUM_PHY_REGS) { 312 device_printf(dev, "Wrong register address.\n"); 313 return (EINVAL); 314 } 315 316 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 317 318 e6000sw_poll_done(sc); 319 val |= 1 << PHY_CMD_SMI_BUSY; 320 val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE; 321 val |= PHY_CMD_OPCODE_READ << PHY_CMD_OPCODE; 322 val |= (reg << PHY_CMD_REG_ADDR) & PHY_CMD_REG_ADDR_MASK; 323 val |= (phy << PHY_CMD_DEV_ADDR) & PHY_CMD_DEV_ADDR_MASK; 324 e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val); 325 e6000sw_poll_done(sc); 326 val = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG) 327 & PHY_DATA_MASK; 328 329 return (val); 330 } 331 332 static int 333 e6000sw_writephy(device_t dev, int phy, int reg, int data) 334 { 335 e6000sw_softc_t *sc; 336 uint32_t val; 337 338 sc = device_get_softc(dev); 339 val = 0; 340 341 if (phy >= E6000SW_NUM_PHYS || reg >= E6000SW_NUM_PHY_REGS) { 342 device_printf(dev, "Wrong register address.\n"); 343 return (EINVAL); 344 } 345 346 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 347 348 e6000sw_poll_done(sc); 349 val |= PHY_CMD_MODE_MDIO << PHY_CMD_MODE; 350 val |= 1 << PHY_CMD_SMI_BUSY; 351 val |= PHY_CMD_OPCODE_WRITE << PHY_CMD_OPCODE; 352 val |= (reg << PHY_CMD_REG_ADDR) & PHY_CMD_REG_ADDR_MASK; 353 val |= (phy << PHY_CMD_DEV_ADDR) & PHY_CMD_DEV_ADDR_MASK; 354 e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, 355 data & PHY_DATA_MASK); 356 e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG, val); 357 e6000sw_poll_done(sc); 358 359 return (0); 360 } 361 362 static int 363 e6000sw_detach(device_t dev) 364 { 365 int phy; 366 e6000sw_softc_t *sc; 367 368 sc = device_get_softc(dev); 369 bus_generic_detach(dev); 370 sx_destroy(&sc->sx); 371 for (phy = 0; phy < E6000SW_NUM_PHYS; phy++) { 372 if (sc->miibus[phy] != NULL) 373 device_delete_child(dev, sc->miibus[phy]); 374 if (sc->ifp[phy] != NULL) 375 if_free(sc->ifp[phy]); 376 if (sc->ifname[phy] != NULL) 377 free(sc->ifname[phy], M_E6000SW); 378 } 379 380 return (0); 381 } 382 383 static etherswitch_info_t* 384 e6000sw_getinfo(device_t dev) 385 { 386 387 return (ðerswitch_info); 388 } 389 390 static void 391 e6000sw_lock(device_t dev) 392 { 393 struct e6000sw_softc *sc; 394 395 sc = device_get_softc(dev); 396 397 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 398 E6000SW_LOCK(sc); 399 } 400 401 static void 402 e6000sw_unlock(device_t dev) 403 { 404 struct e6000sw_softc *sc; 405 406 sc = device_get_softc(dev); 407 408 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 409 E6000SW_UNLOCK(sc); 410 } 411 412 static int 413 e6000sw_getport(device_t dev, etherswitch_port_t *p) 414 { 415 struct mii_data *mii; 416 int err; 417 struct ifmediareq *ifmr; 418 419 err = 0; 420 e6000sw_softc_t *sc = device_get_softc(dev); 421 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 422 423 E6000SW_LOCK(sc); 424 425 if (p->es_port >= E6000SW_NUM_PORTS || 426 p->es_port < 0) { 427 err = EINVAL; 428 goto out; 429 } 430 431 e6000sw_get_pvid(sc, p->es_port, &p->es_pvid); 432 433 if (e6000sw_cpuport(sc, p->es_port)) { 434 p->es_flags |= ETHERSWITCH_PORT_CPU; 435 ifmr = &p->es_ifmr; 436 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 437 ifmr->ifm_count = 0; 438 ifmr->ifm_current = ifmr->ifm_active = 439 IFM_ETHER | IFM_1000_T | IFM_FDX; 440 ifmr->ifm_mask = 0; 441 } else { 442 mii = e6000sw_miiforphy(sc, p->es_port); 443 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 444 &mii->mii_media, SIOCGIFMEDIA); 445 } 446 447 out: 448 E6000SW_UNLOCK(sc); 449 return (err); 450 } 451 452 static int 453 e6000sw_setport(device_t dev, etherswitch_port_t *p) 454 { 455 e6000sw_softc_t *sc; 456 int err; 457 struct mii_data *mii; 458 459 err = 0; 460 sc = device_get_softc(dev); 461 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 462 463 E6000SW_LOCK(sc); 464 465 if (p->es_port >= E6000SW_NUM_PORTS || 466 p->es_port < 0) { 467 err = EINVAL; 468 goto out; 469 } 470 471 if (p->es_pvid != 0) 472 e6000sw_set_pvid(sc, p->es_port, p->es_pvid); 473 if (!e6000sw_cpuport(sc, p->es_port)) { 474 mii = e6000sw_miiforphy(sc, p->es_port); 475 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media, 476 SIOCSIFMEDIA); 477 } 478 479 out: 480 E6000SW_UNLOCK(sc); 481 return (err); 482 } 483 484 /* 485 * Registers in this switch are divided into sections, specified in 486 * documentation. So as to access any of them, section index and reg index 487 * is necessary. etherswitchcfg uses only one variable, so indexes were 488 * compressed into addr_reg: 32 * section_index + reg_index. 489 */ 490 static int 491 e6000sw_readreg_wrapper(device_t dev, int addr_reg) 492 { 493 494 if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) || 495 (addr_reg < (REG_PORT(0) * 32))) { 496 device_printf(dev, "Wrong register address.\n"); 497 return (EINVAL); 498 } 499 500 return (e6000sw_readreg(device_get_softc(dev), addr_reg / 32, 501 addr_reg % 32)); 502 } 503 504 static int 505 e6000sw_writereg_wrapper(device_t dev, int addr_reg, int val) 506 { 507 508 if ((addr_reg > (REG_GLOBAL2 * 32 + REG_NUM_MAX)) || 509 (addr_reg < (REG_PORT(0) * 32))) { 510 device_printf(dev, "Wrong register address.\n"); 511 return (EINVAL); 512 } 513 e6000sw_writereg(device_get_softc(dev), addr_reg / 5, 514 addr_reg % 32, val); 515 516 return (0); 517 } 518 519 /* 520 * These wrappers are necessary because PHY accesses from etherswitchcfg 521 * need to be synchronized with locks, while miibus PHY accesses do not. 522 */ 523 static int 524 e6000sw_readphy_wrapper(device_t dev, int phy, int reg) 525 { 526 e6000sw_softc_t *sc; 527 int ret; 528 529 sc = device_get_softc(dev); 530 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 531 532 E6000SW_LOCK(sc); 533 ret = e6000sw_readphy(dev, phy, reg); 534 E6000SW_UNLOCK(sc); 535 536 return (ret); 537 } 538 539 static int 540 e6000sw_writephy_wrapper(device_t dev, int phy, int reg, int data) 541 { 542 e6000sw_softc_t *sc; 543 int ret; 544 545 sc = device_get_softc(dev); 546 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 547 548 E6000SW_LOCK(sc); 549 ret = e6000sw_writephy(dev, phy, reg, data); 550 E6000SW_UNLOCK(sc); 551 552 return (ret); 553 } 554 555 /* 556 * setvgroup/getvgroup called from etherswitchfcg need to be locked, 557 * while internal calls do not. 558 */ 559 static int 560 e6000sw_setvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg) 561 { 562 e6000sw_softc_t *sc; 563 int ret; 564 565 sc = device_get_softc(dev); 566 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 567 568 E6000SW_LOCK(sc); 569 ret = e6000sw_setvgroup(dev, vg); 570 E6000SW_UNLOCK(sc); 571 572 return (ret); 573 } 574 575 static int 576 e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vlangroup_t *vg) 577 { 578 e6000sw_softc_t *sc; 579 int ret; 580 581 sc = device_get_softc(dev); 582 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 583 584 E6000SW_LOCK(sc); 585 ret = e6000sw_getvgroup(dev, vg); 586 E6000SW_UNLOCK(sc); 587 588 return (ret); 589 } 590 591 static __inline void 592 e6000sw_flush_port(e6000sw_softc_t *sc, int port) 593 { 594 uint32_t reg; 595 596 reg = e6000sw_readreg(sc, REG_PORT(port), 597 PORT_VLAN_MAP); 598 reg &= ~PORT_VLAN_MAP_TABLE_MASK; 599 reg &= ~PORT_VLAN_MAP_FID_MASK; 600 e6000sw_writereg(sc, REG_PORT(port), 601 PORT_VLAN_MAP, reg); 602 if (sc->vgroup[port] != E6000SW_PORT_NO_VGROUP) { 603 /* 604 * If port belonged somewhere, owner-group 605 * should have its entry removed. 606 */ 607 sc->members[sc->vgroup[port]] &= ~(1 << port); 608 sc->vgroup[port] = E6000SW_PORT_NO_VGROUP; 609 } 610 } 611 612 static __inline void 613 e6000sw_port_assign_vgroup(e6000sw_softc_t *sc, int port, int fid, int vgroup, 614 int members) 615 { 616 uint32_t reg; 617 618 reg = e6000sw_readreg(sc, REG_PORT(port), 619 PORT_VLAN_MAP); 620 reg &= ~PORT_VLAN_MAP_TABLE_MASK; 621 reg &= ~PORT_VLAN_MAP_FID_MASK; 622 reg |= members & ~(1 << port); 623 reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK; 624 e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, 625 reg); 626 sc->vgroup[port] = vgroup; 627 } 628 629 static int 630 e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 631 { 632 e6000sw_softc_t *sc; 633 int port, fid; 634 635 sc = device_get_softc(dev); 636 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 637 638 if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS) 639 return (EINVAL); 640 if (vg->es_member_ports != vg->es_untagged_ports) { 641 device_printf(dev, "Tagged ports not supported.\n"); 642 return (EINVAL); 643 } 644 645 vg->es_untagged_ports &= PORT_VLAN_MAP_TABLE_MASK; 646 fid = vg->es_vlangroup + 1; 647 for (port = 0; port < E6000SW_NUM_PORTS; port++) { 648 if ((sc->members[vg->es_vlangroup] & (1 << port)) || 649 (vg->es_untagged_ports & (1 << port))) 650 e6000sw_flush_port(sc, port); 651 if (vg->es_untagged_ports & (1 << port)) 652 e6000sw_port_assign_vgroup(sc, port, fid, 653 vg->es_vlangroup, vg->es_untagged_ports); 654 } 655 sc->vid[vg->es_vlangroup] = vg->es_vid; 656 sc->members[vg->es_vlangroup] = vg->es_untagged_ports; 657 658 return (0); 659 } 660 661 static int 662 e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 663 { 664 e6000sw_softc_t *sc; 665 666 sc = device_get_softc(dev); 667 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 668 669 if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS) 670 return (EINVAL); 671 vg->es_untagged_ports = vg->es_member_ports = 672 sc->members[vg->es_vlangroup]; 673 vg->es_vid = ETHERSWITCH_VID_VALID; 674 675 return (0); 676 } 677 678 static __inline struct mii_data* 679 e6000sw_miiforphy(e6000sw_softc_t *sc, unsigned int phy) 680 { 681 682 if (phy >= E6000SW_NUM_PHYS) 683 return (NULL); 684 685 return (device_get_softc(sc->miibus[phy])); 686 } 687 688 static int 689 e6000sw_ifmedia_upd(struct ifnet *ifp) 690 { 691 e6000sw_softc_t *sc; 692 struct mii_data *mii; 693 694 sc = ifp->if_softc; 695 mii = e6000sw_miiforphy(sc, ifp->if_dunit); 696 if (mii == NULL) 697 return (ENXIO); 698 mii_mediachg(mii); 699 700 return (0); 701 } 702 703 static void 704 e6000sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 705 { 706 e6000sw_softc_t *sc; 707 struct mii_data *mii; 708 709 sc = ifp->if_softc; 710 mii = e6000sw_miiforphy(sc, ifp->if_dunit); 711 712 if (mii == NULL) 713 return; 714 715 mii_pollstat(mii); 716 ifmr->ifm_active = mii->mii_media_active; 717 ifmr->ifm_status = mii->mii_media_status; 718 } 719 720 static __inline uint32_t 721 e6000sw_readreg(e6000sw_softc_t *sc, int addr, int reg) 722 { 723 724 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 725 726 return (MDIO_READREG(device_get_parent(sc->dev), addr, reg)); 727 } 728 729 static __inline void 730 e6000sw_writereg(e6000sw_softc_t *sc, int addr, int reg, int val) 731 { 732 733 E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); 734 735 MDIO_WRITEREG(device_get_parent(sc->dev), addr, reg, val); 736 } 737 738 static __inline int 739 e6000sw_cpuport(e6000sw_softc_t *sc, int port) 740 { 741 742 return (sc->cpuports_mask & (1 << port)); 743 } 744 745 static __inline int 746 e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid) 747 { 748 749 e6000sw_writereg(sc, REG_PORT(port), PORT_VID, pvid & 750 PORT_VID_DEF_VID_MASK); 751 752 return (0); 753 } 754 755 static __inline int 756 e6000sw_get_pvid(e6000sw_softc_t *sc, int port, int *pvid) 757 { 758 759 if (pvid == NULL) 760 return (ENXIO); 761 762 *pvid = e6000sw_readreg(sc, REG_PORT(port), PORT_VID) & 763 PORT_VID_DEF_VID_MASK; 764 765 return (0); 766 } 767 768 static void 769 e6000sw_tick (void *arg) 770 { 771 e6000sw_softc_t *sc; 772 struct mii_softc *miisc; 773 int i; 774 775 sc = arg; 776 777 E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); 778 for (;;) { 779 E6000SW_LOCK(sc); 780 for (i = 0; i < E6000SW_NUM_PHYS; i++) { 781 mii_tick(sc->mii[i]); 782 LIST_FOREACH(miisc, &sc->mii[i]->mii_phys, mii_list) { 783 if (IFM_INST(sc->mii[i]->mii_media.ifm_cur->ifm_media) 784 != miisc->mii_inst) 785 continue; 786 mii_phy_update(miisc, MII_POLLSTAT); 787 } 788 } 789 E6000SW_UNLOCK(sc); 790 pause("e6000sw tick", 1000); 791 } 792 } 793 794 static void 795 e6000sw_setup(device_t dev, e6000sw_softc_t *sc) 796 { 797 uint16_t atu_ctrl, atu_age; 798 799 /* Set aging time */ 800 e6000sw_writereg(sc, REG_GLOBAL, ATU_CONTROL, 801 (E6000SW_DEFAULT_AGETIME << ATU_CONTROL_AGETIME) | 802 (1 << ATU_CONTROL_LEARN2ALL)); 803 804 /* Send all with specific mac address to cpu port */ 805 e6000sw_writereg(sc, REG_GLOBAL2, MGMT_EN_2x, MGMT_EN_ALL); 806 e6000sw_writereg(sc, REG_GLOBAL2, MGMT_EN_0x, MGMT_EN_ALL); 807 808 /* Disable Remote Managment */ 809 e6000sw_writereg(sc, REG_GLOBAL, SWITCH_GLOBAL_CONTROL2, 0); 810 811 /* Disable loopback filter and flow control messages */ 812 e6000sw_writereg(sc, REG_GLOBAL2, SWITCH_MGMT, 813 SWITCH_MGMT_PRI_MASK | 814 (1 << SWITCH_MGMT_RSVD2CPU) | 815 SWITCH_MGMT_FC_PRI_MASK | 816 (1 << SWITCH_MGMT_FORCEFLOW)); 817 818 /* Set VLAN configuration */ 819 e6000sw_port_vlan_conf(sc); 820 821 e6000sw_atu_flush(dev, sc, NO_OPERATION); 822 e6000sw_atu_mac_table(dev, sc, NULL, NO_OPERATION); 823 e6000sw_set_atustat(dev, sc, 0, COUNT_ALL); 824 825 /* Set ATU AgeTime to 15 seconds */ 826 atu_age = 1; 827 828 atu_ctrl = e6000sw_readreg(sc, REG_GLOBAL, ATU_CONTROL); 829 830 /* Set new AgeTime field */ 831 atu_ctrl &= ~ATU_CONTROL_AGETIME_MASK; 832 e6000sw_writereg(sc, REG_GLOBAL, ATU_CONTROL, atu_ctrl | 833 (atu_age << ATU_CONTROL_AGETIME)); 834 } 835 836 static void 837 e6000sw_port_vlan_conf(e6000sw_softc_t *sc) 838 { 839 int port, ret; 840 etherswitch_vlangroup_t vg; 841 device_t dev; 842 843 dev = sc->dev; 844 /* Disable all ports */ 845 for (port = 0; port < E6000SW_NUM_PORTS; port++) { 846 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL); 847 e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, 848 (ret & ~PORT_CONTROL_ENABLE)); 849 } 850 851 /* Set port priority */ 852 for (port = 0; port < E6000SW_NUM_PORTS; port++) { 853 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID); 854 ret &= ~PORT_VID_PRIORITY_MASK; 855 e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret); 856 } 857 858 vg.es_vlangroup = 0; 859 vg.es_vid = 0; 860 vg.es_member_ports = vg.es_untagged_ports = E6000SW_DEF_VLANGROUP0; 861 e6000sw_setvgroup(dev, &vg); 862 vg.es_vlangroup = 1; 863 vg.es_vid = 1; 864 vg.es_member_ports = vg.es_untagged_ports = E6000SW_DEF_VLANGROUP1; 865 e6000sw_setvgroup(dev, &vg); 866 867 device_printf(dev, "Default vlangroups set.\n"); 868 /* Set VID map */ 869 for (port = 0; port < E6000SW_NUM_PORTS; port++) { 870 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID); 871 ret &= ~PORT_VID_DEF_VID_MASK; 872 ret |= (port + 1); 873 e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret); 874 } 875 876 /* Enable all ports */ 877 for (port = 0; port < E6000SW_NUM_PORTS; port++) { 878 ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL); 879 e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, (ret | 880 PORT_CONTROL_ENABLE)); 881 } 882 } 883 884 static void 885 e6000sw_set_atustat(device_t dev, e6000sw_softc_t *sc, int bin, int flag) 886 { 887 uint16_t ret; 888 889 ret = e6000sw_readreg(sc, REG_GLOBAL2, ATU_STATS); 890 e6000sw_writereg(sc, REG_GLOBAL2, ATU_STATS, (bin << ATU_STATS_BIN ) | 891 (flag << ATU_STATS_FLAG)); 892 } 893 894 static int 895 e6000sw_atu_mac_table(device_t dev, e6000sw_softc_t *sc, struct atu_opt *atu, 896 int flag) 897 { 898 uint16_t ret_opt; 899 uint16_t ret_data; 900 int retries; 901 902 if (flag == NO_OPERATION) 903 return (0); 904 else if ((flag & (LOAD_FROM_FIB | PURGE_FROM_FIB | GET_NEXT_IN_FIB | 905 GET_VIOLATION_DATA | CLEAR_VIOLATION_DATA)) == 0) { 906 device_printf(dev, "Wrong Opcode for ATU operation\n"); 907 return (EINVAL); 908 } 909 910 ret_opt = e6000sw_readreg(sc, REG_GLOBAL, ATU_OPERATION); 911 912 if (ret_opt & ATU_UNIT_BUSY) { 913 device_printf(dev, "ATU unit is busy, cannot access" 914 "register\n"); 915 return (EBUSY); 916 } else { 917 if(flag & LOAD_FROM_FIB) { 918 ret_data = e6000sw_readreg(sc, REG_GLOBAL, ATU_DATA); 919 e6000sw_writereg(sc, REG_GLOBAL2, ATU_DATA, (ret_data & 920 ~ENTRY_STATE)); 921 } 922 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR01, atu->mac_01); 923 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR23, atu->mac_23); 924 e6000sw_writereg(sc, REG_GLOBAL, ATU_MAC_ADDR45, atu->mac_45); 925 e6000sw_writereg(sc, REG_GLOBAL, ATU_FID, atu->fid); 926 927 e6000sw_writereg(sc, REG_GLOBAL, ATU_OPERATION, (ret_opt | 928 ATU_UNIT_BUSY | flag)); 929 930 retries = E6000SW_RETRIES; 931 while (--retries & (e6000sw_readreg(sc, REG_GLOBAL, 932 ATU_OPERATION) & ATU_UNIT_BUSY)) 933 DELAY(1); 934 935 if (retries == 0) 936 device_printf(dev, "Timeout while flushing\n"); 937 else if (flag & GET_NEXT_IN_FIB) { 938 atu->mac_01 = e6000sw_readreg(sc, REG_GLOBAL, 939 ATU_MAC_ADDR01); 940 atu->mac_23 = e6000sw_readreg(sc, REG_GLOBAL, 941 ATU_MAC_ADDR23); 942 atu->mac_45 = e6000sw_readreg(sc, REG_GLOBAL, 943 ATU_MAC_ADDR45); 944 } 945 } 946 947 return (0); 948 } 949 950 static int 951 e6000sw_atu_flush(device_t dev, e6000sw_softc_t *sc, int flag) 952 { 953 uint16_t ret; 954 int retries; 955 956 if (flag == NO_OPERATION) 957 return (0); 958 959 ret = e6000sw_readreg(sc, REG_GLOBAL, ATU_OPERATION); 960 if (ret & ATU_UNIT_BUSY) { 961 device_printf(dev, "Atu unit is busy, cannot flush\n"); 962 return (EBUSY); 963 } else { 964 e6000sw_writereg(sc, REG_GLOBAL, ATU_OPERATION, (ret | 965 ATU_UNIT_BUSY | flag)); 966 retries = E6000SW_RETRIES; 967 while (--retries & (e6000sw_readreg(sc, REG_GLOBAL, 968 ATU_OPERATION) & ATU_UNIT_BUSY)) 969 DELAY(1); 970 971 if (retries == 0) 972 device_printf(dev, "Timeout while flushing\n"); 973 } 974 975 return (0); 976 } 977