1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2022 Adrian Chadd <adrian@FreeBSD.org>. 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/param.h> 29 #include <sys/bus.h> 30 #include <sys/errno.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/socket.h> 35 #include <sys/sockio.h> 36 #include <sys/sysctl.h> 37 #include <sys/systm.h> 38 39 #include <net/if.h> 40 #include <net/if_var.h> 41 #include <net/if_arp.h> 42 #include <net/ethernet.h> 43 #include <net/if_dl.h> 44 #include <net/if_media.h> 45 #include <net/if_types.h> 46 47 #include <machine/bus.h> 48 #include <dev/iicbus/iic.h> 49 #include <dev/iicbus/iiconf.h> 50 #include <dev/iicbus/iicbus.h> 51 #include <dev/mii/mii.h> 52 #include <dev/mii/miivar.h> 53 #include <dev/mdio/mdio.h> 54 #include <dev/extres/clk/clk.h> 55 #include <dev/extres/hwreset/hwreset.h> 56 57 #include <dev/fdt/fdt_common.h> 58 #include <dev/ofw/ofw_bus.h> 59 #include <dev/ofw/ofw_bus_subr.h> 60 61 #include <dev/etherswitch/etherswitch.h> 62 63 #include <dev/etherswitch/ar40xx/ar40xx_var.h> 64 #include <dev/etherswitch/ar40xx/ar40xx_reg.h> 65 #include <dev/etherswitch/ar40xx/ar40xx_phy.h> 66 #include <dev/etherswitch/ar40xx/ar40xx_debug.h> 67 #include <dev/etherswitch/ar40xx/ar40xx_hw.h> 68 #include <dev/etherswitch/ar40xx/ar40xx_hw_psgmii.h> 69 #include <dev/etherswitch/ar40xx/ar40xx_hw_port.h> 70 #include <dev/etherswitch/ar40xx/ar40xx_hw_mib.h> 71 #include <dev/etherswitch/ar40xx/ar40xx_hw_vtu.h> 72 #include <dev/etherswitch/ar40xx/ar40xx_hw_atu.h> 73 74 #include "mdio_if.h" 75 #include "miibus_if.h" 76 #include "etherswitch_if.h" 77 78 static struct ofw_compat_data compat_data[] = { 79 { "qcom,ess-switch", 1 }, 80 { NULL, 0 }, 81 }; 82 83 static int 84 ar40xx_probe(device_t dev) 85 { 86 87 if (! ofw_bus_status_okay(dev)) 88 return (ENXIO); 89 90 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 91 return (ENXIO); 92 93 device_set_desc(dev, "IPQ4018 ESS Switch fabric / PSGMII PHY"); 94 return (BUS_PROBE_DEFAULT); 95 } 96 97 static void 98 ar40xx_tick(void *arg) 99 { 100 struct ar40xx_softc *sc = arg; 101 102 (void) ar40xx_phy_tick(sc); 103 callout_reset(&sc->sc_phy_callout, hz, ar40xx_tick, sc); 104 } 105 106 static void 107 ar40xx_statchg(device_t dev) 108 { 109 struct ar40xx_softc *sc = device_get_softc(dev); 110 111 AR40XX_DPRINTF(sc, AR40XX_DBG_PORT_STATUS, "%s\n", __func__); 112 } 113 114 static int 115 ar40xx_readphy(device_t dev, int phy, int reg) 116 { 117 struct ar40xx_softc *sc = device_get_softc(dev); 118 119 return MDIO_READREG(sc->sc_mdio_dev, phy, reg); 120 } 121 122 static int 123 ar40xx_writephy(device_t dev, int phy, int reg, int val) 124 { 125 struct ar40xx_softc *sc = device_get_softc(dev); 126 127 return MDIO_WRITEREG(sc->sc_mdio_dev, phy, reg, val); 128 } 129 130 /* 131 * Do the initial switch configuration. 132 */ 133 static int 134 ar40xx_reset_switch(struct ar40xx_softc *sc) 135 { 136 int ret, i; 137 138 AR40XX_DPRINTF(sc, AR40XX_DBG_HW_INIT, "%s: called\n", __func__); 139 140 /* blank the VLAN config */ 141 memset(&sc->sc_vlan, 0, sizeof(sc->sc_vlan)); 142 143 /* initial vlan port mapping */ 144 for (i = 0; i < AR40XX_NUM_VTU_ENTRIES; i++) 145 sc->sc_vlan.vlan_id[i] = 0; 146 147 /* init vlan config */ 148 ret = ar40xx_hw_vlan_init(sc); 149 150 /* init monitor config */ 151 sc->sc_monitor.mirror_tx = false; 152 sc->sc_monitor.mirror_rx = false; 153 sc->sc_monitor.source_port = 0; 154 sc->sc_monitor.monitor_port = 0; 155 156 /* apply switch config */ 157 ret = ar40xx_hw_sw_hw_apply(sc); 158 159 return (ret); 160 } 161 162 static int 163 ar40xx_sysctl_dump_port_state(SYSCTL_HANDLER_ARGS) 164 { 165 struct ar40xx_softc *sc = arg1; 166 int val = 0; 167 int error; 168 int i; 169 170 (void) i; (void) sc; 171 172 error = sysctl_handle_int(oidp, &val, 0, req); 173 if (error || !req->newptr) 174 return (error); 175 176 if (val < 0 || val > 5) { 177 return (EINVAL); 178 } 179 180 AR40XX_LOCK(sc); 181 182 device_printf(sc->sc_dev, "port %d: PORT_STATUS=0x%08x\n", val, 183 AR40XX_REG_READ(sc, AR40XX_REG_PORT_STATUS(val))); 184 device_printf(sc->sc_dev, "port %d: PORT_HEADER=0x%08x\n", val, 185 AR40XX_REG_READ(sc, AR40XX_REG_PORT_HEADER(val))); 186 device_printf(sc->sc_dev, "port %d: PORT_VLAN0=0x%08x\n", val, 187 AR40XX_REG_READ(sc, AR40XX_REG_PORT_VLAN0(val))); 188 device_printf(sc->sc_dev, "port %d: PORT_VLAN1=0x%08x\n", val, 189 AR40XX_REG_READ(sc, AR40XX_REG_PORT_VLAN1(val))); 190 device_printf(sc->sc_dev, "port %d: PORT_LOOKUP=0x%08x\n", val, 191 AR40XX_REG_READ(sc, AR40XX_REG_PORT_LOOKUP(val))); 192 device_printf(sc->sc_dev, "port %d: PORT_HOL_CTRL1=0x%08x\n", val, 193 AR40XX_REG_READ(sc, AR40XX_REG_PORT_HOL_CTRL1(val))); 194 device_printf(sc->sc_dev, "port %d: PORT_FLOWCTRL_THRESH=0x%08x\n", 195 val, AR40XX_REG_READ(sc, AR40XX_REG_PORT_FLOWCTRL_THRESH(val))); 196 197 AR40XX_UNLOCK(sc); 198 199 return (0); 200 } 201 202 static int 203 ar40xx_sysctl_dump_port_mibstats(SYSCTL_HANDLER_ARGS) 204 { 205 struct ar40xx_softc *sc = arg1; 206 int val = 0; 207 int error; 208 int i; 209 210 (void) i; (void) sc; 211 212 error = sysctl_handle_int(oidp, &val, 0, req); 213 if (error || !req->newptr) 214 return (error); 215 216 if (val < 0 || val > 5) { 217 return (EINVAL); 218 } 219 220 AR40XX_LOCK(sc); 221 222 /* Yes, this snapshots all ports */ 223 (void) ar40xx_hw_mib_capture(sc); 224 (void) ar40xx_hw_mib_fetch(sc, val); 225 226 AR40XX_UNLOCK(sc); 227 228 return (0); 229 } 230 231 232 static int 233 ar40xx_sysctl_attach(struct ar40xx_softc *sc) 234 { 235 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 236 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 237 238 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 239 "debug", CTLFLAG_RW, &sc->sc_debug, 0, 240 "debugging flags"); 241 242 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 243 "port_state", CTLTYPE_INT | CTLFLAG_RW, sc, 244 0, ar40xx_sysctl_dump_port_state, "I", ""); 245 246 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 247 "port_mibstats", CTLTYPE_INT | CTLFLAG_RW, sc, 248 0, ar40xx_sysctl_dump_port_mibstats, "I", ""); 249 250 return (0); 251 } 252 253 static int 254 ar40xx_detach(device_t dev) 255 { 256 struct ar40xx_softc *sc = device_get_softc(dev); 257 int i; 258 259 device_printf(sc->sc_dev, "%s: called\n", __func__); 260 261 callout_drain(&sc->sc_phy_callout); 262 263 /* Free PHYs */ 264 for (i = 0; i < AR40XX_NUM_PHYS; i++) { 265 if (sc->sc_phys.miibus[i] != NULL) 266 device_delete_child(dev, sc->sc_phys.miibus[i]); 267 if (sc->sc_phys.ifp[i] != NULL) 268 if_free(sc->sc_phys.ifp[i]); 269 free(sc->sc_phys.ifname[i], M_DEVBUF); 270 } 271 272 bus_generic_detach(dev); 273 mtx_destroy(&sc->sc_mtx); 274 275 return (0); 276 } 277 278 static int 279 ar40xx_attach(device_t dev) 280 { 281 struct ar40xx_softc *sc = device_get_softc(dev); 282 phandle_t psgmii_p, root_p, mdio_p; 283 int ret, i; 284 285 sc->sc_dev = dev; 286 mtx_init(&sc->sc_mtx, "ar40xx_switch", NULL, MTX_DEF); 287 288 psgmii_p = OF_finddevice("/soc/ess-psgmii"); 289 if (psgmii_p == -1) { 290 device_printf(dev, 291 "%s: couldn't find /soc/ess-psgmii DT node\n", 292 __func__); 293 goto error; 294 } 295 296 /* 297 * Get the ipq4019-mdio node here, to talk to our local PHYs 298 * if needed 299 */ 300 root_p = OF_finddevice("/soc"); 301 mdio_p = ofw_bus_find_compatible(root_p, "qcom,ipq4019-mdio"); 302 if (mdio_p == -1) { 303 device_printf(dev, "%s: couldn't find ipq4019-mdio DT node\n", 304 __func__); 305 goto error; 306 } 307 sc->sc_mdio_phandle = mdio_p; 308 sc->sc_mdio_dev = OF_device_from_xref(OF_xref_from_node(mdio_p)); 309 if (sc->sc_mdio_dev == NULL) { 310 device_printf(dev, 311 "%s: couldn't get mdio device (mdio_p=%u)\n", 312 __func__, mdio_p); 313 goto error; 314 } 315 316 /* get psgmii base address from psgmii node */ 317 ret = OF_decode_addr(psgmii_p, 0, &sc->sc_psgmii_mem_tag, 318 &sc->sc_psgmii_mem_handle, 319 &sc->sc_psgmii_mem_size); 320 if (ret != 0) { 321 device_printf(dev, "%s: couldn't map psgmii mem (%d)\n", 322 __func__, ret); 323 goto error; 324 } 325 326 /* get switch base address */ 327 sc->sc_ess_mem_rid = 0; 328 sc->sc_ess_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 329 &sc->sc_ess_mem_rid, RF_ACTIVE); 330 if (sc->sc_ess_mem_res == NULL) { 331 device_printf(dev, "%s: failed to find memory resource\n", 332 __func__); 333 goto error; 334 } 335 sc->sc_ess_mem_size = (size_t) bus_get_resource_count(dev, 336 SYS_RES_MEMORY, sc->sc_ess_mem_rid); 337 if (sc->sc_ess_mem_size == 0) { 338 device_printf(dev, "%s: failed to get device memory size\n", 339 __func__); 340 goto error; 341 } 342 343 ret = OF_getencprop(ofw_bus_get_node(dev), "switch_mac_mode", 344 &sc->sc_config.switch_mac_mode, 345 sizeof(sc->sc_config.switch_mac_mode)); 346 if (ret < 0) { 347 device_printf(dev, "%s: missing switch_mac_mode property\n", 348 __func__); 349 goto error; 350 } 351 352 ret = OF_getencprop(ofw_bus_get_node(dev), "switch_cpu_bmp", 353 &sc->sc_config.switch_cpu_bmp, 354 sizeof(sc->sc_config.switch_cpu_bmp)); 355 if (ret < 0) { 356 device_printf(dev, "%s: missing switch_cpu_bmp property\n", 357 __func__); 358 goto error; 359 } 360 361 ret = OF_getencprop(ofw_bus_get_node(dev), "switch_lan_bmp", 362 &sc->sc_config.switch_lan_bmp, 363 sizeof(sc->sc_config.switch_lan_bmp)); 364 if (ret < 0) { 365 device_printf(dev, "%s: missing switch_lan_bmp property\n", 366 __func__); 367 goto error; 368 } 369 370 ret = OF_getencprop(ofw_bus_get_node(dev), "switch_wan_bmp", 371 &sc->sc_config.switch_wan_bmp, 372 sizeof(sc->sc_config.switch_wan_bmp)); 373 if (ret < 0) { 374 device_printf(dev, "%s: missing switch_wan_bmp property\n", 375 __func__); 376 goto error; 377 } 378 379 ret = clk_get_by_ofw_name(dev, 0, "ess_clk", &sc->sc_ess_clk); 380 if (ret != 0) { 381 device_printf(dev, "%s: failed to find ess_clk (%d)\n", 382 __func__, ret); 383 goto error; 384 } 385 ret = clk_enable(sc->sc_ess_clk); 386 if (ret != 0) { 387 device_printf(dev, "%s: failed to enable clock (%d)\n", 388 __func__, ret); 389 goto error; 390 } 391 392 ret = hwreset_get_by_ofw_name(dev, 0, "ess_rst", &sc->sc_ess_rst); 393 if (ret != 0) { 394 device_printf(dev, "%s: failed to find ess_rst (%d)\n", 395 __func__, ret); 396 goto error; 397 } 398 399 /* 400 * Ok, at this point we have enough resources to do an initial 401 * reset and configuration. 402 */ 403 404 AR40XX_LOCK(sc); 405 406 /* Initial PSGMII/RGMII port configuration */ 407 ret = ar40xx_hw_psgmii_init_config(sc); 408 if (ret != 0) { 409 device_printf(sc->sc_dev, 410 "ERROR: failed to init PSGMII (%d)\n", ret); 411 goto error_locked; 412 } 413 414 /* 415 * ESS reset - this resets both the ethernet switch 416 * AND the ethernet block. 417 */ 418 ret = ar40xx_hw_ess_reset(sc); 419 if (ret != 0) { 420 device_printf(sc->sc_dev, 421 "ERROR: failed to reset ESS block (%d)\n", ret); 422 goto error_locked; 423 } 424 425 /* 426 * Check the PHY IDs for each of the PHYs from 0..4; 427 * this is useful to make sure that we can SEE the external 428 * PHY(s). 429 */ 430 if (bootverbose) { 431 ret = ar40xx_hw_phy_get_ids(sc); 432 if (ret != 0) { 433 device_printf(sc->sc_dev, 434 "ERROR: failed to check PHY IDs (%d)\n", ret); 435 goto error_locked; 436 } 437 } 438 439 /* 440 * Do PSGMII PHY self-test; work-around issues. 441 */ 442 ret = ar40xx_hw_psgmii_self_test(sc); 443 if (ret != 0) { 444 device_printf(sc->sc_dev, 445 "ERROR: failed to do PSGMII self-test (%d)\n", ret); 446 goto error_locked; 447 } 448 449 /* Return port config to runtime state */ 450 ret = ar40xx_hw_psgmii_self_test_clean(sc); 451 if (ret != 0) { 452 device_printf(sc->sc_dev, 453 "ERROR: failed to do PSGMII runtime config (%d)\n", ret); 454 goto error_locked; 455 } 456 457 /* mac_mode_init */ 458 ret = ar40xx_hw_psgmii_set_mac_mode(sc, 459 sc->sc_config.switch_mac_mode); 460 461 /* Initialise each hardware port */ 462 for (i = 0; i < AR40XX_NUM_PORTS; i++) { 463 ret = ar40xx_hw_port_init(sc, i); 464 } 465 466 /* initialise the global switch configuration */ 467 ret = ar40xx_hw_init_globals(sc); 468 469 /* reset the switch vlan/port learning config */ 470 ret = ar40xx_reset_switch(sc); 471 472 /* cpuport setup */ 473 ret = ar40xx_hw_port_cpuport_setup(sc); 474 475 AR40XX_UNLOCK(sc); 476 477 #if 0 478 /* We may end up needing the QM workaround code here.. */ 479 device_printf(dev, "%s: TODO: QM error check\n", __func__); 480 #endif 481 482 /* Attach PHYs */ 483 ret = ar40xx_attach_phys(sc); 484 485 ret = bus_generic_probe(dev); 486 bus_enumerate_hinted_children(dev); 487 ret = bus_generic_attach(dev); 488 489 /* Start timer */ 490 callout_init_mtx(&sc->sc_phy_callout, &sc->sc_mtx, 0); 491 492 /* 493 * Setup the etherswitch info block. 494 */ 495 strlcpy(sc->sc_info.es_name, device_get_desc(dev), 496 sizeof(sc->sc_info.es_name)); 497 sc->sc_info.es_nports = AR40XX_NUM_PORTS; 498 sc->sc_info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q; 499 /* XXX TODO: double-tag / 802.1ad */ 500 sc->sc_info.es_nvlangroups = AR40XX_NUM_VTU_ENTRIES; 501 502 /* 503 * Fetch the initial port configuration. 504 */ 505 AR40XX_LOCK(sc); 506 ar40xx_tick(sc); 507 AR40XX_UNLOCK(sc); 508 509 ar40xx_sysctl_attach(sc); 510 511 return (0); 512 error_locked: 513 AR40XX_UNLOCK(sc); 514 error: 515 ar40xx_detach(dev); 516 return (ENXIO); 517 } 518 519 static void 520 ar40xx_lock(device_t dev) 521 { 522 struct ar40xx_softc *sc = device_get_softc(dev); 523 524 AR40XX_LOCK(sc); 525 } 526 527 static void 528 ar40xx_unlock(device_t dev) 529 { 530 struct ar40xx_softc *sc = device_get_softc(dev); 531 532 AR40XX_LOCK_ASSERT(sc); 533 AR40XX_UNLOCK(sc); 534 } 535 536 static etherswitch_info_t * 537 ar40xx_getinfo(device_t dev) 538 { 539 struct ar40xx_softc *sc = device_get_softc(dev); 540 541 return (&sc->sc_info); 542 } 543 544 static int 545 ar40xx_readreg(device_t dev, int addr) 546 { 547 struct ar40xx_softc *sc = device_get_softc(dev); 548 549 if (addr >= sc->sc_ess_mem_size - 1) 550 return (-1); 551 552 AR40XX_REG_BARRIER_READ(sc); 553 554 return AR40XX_REG_READ(sc, addr); 555 } 556 557 static int 558 ar40xx_writereg(device_t dev, int addr, int value) 559 { 560 struct ar40xx_softc *sc = device_get_softc(dev); 561 562 if (addr >= sc->sc_ess_mem_size - 1) 563 return (-1); 564 565 AR40XX_REG_WRITE(sc, addr, value); 566 AR40XX_REG_BARRIER_WRITE(sc); 567 return (0); 568 } 569 570 /* 571 * Get the port configuration and status. 572 */ 573 static int 574 ar40xx_getport(device_t dev, etherswitch_port_t *p) 575 { 576 struct ar40xx_softc *sc = device_get_softc(dev); 577 struct mii_data *mii = NULL; 578 struct ifmediareq *ifmr; 579 int err; 580 581 if (p->es_port < 0 || p->es_port > sc->sc_info.es_nports) 582 return (ENXIO); 583 584 AR40XX_LOCK(sc); 585 /* Fetch the current VLAN configuration for this port */ 586 /* PVID */ 587 ar40xx_hw_get_port_pvid(sc, p->es_port, &p->es_pvid); 588 589 /* 590 * The VLAN egress aren't appropriate to the ports; 591 * instead it's part of the VLAN group config. 592 */ 593 594 /* Get MII config */ 595 mii = ar40xx_phy_miiforport(sc, p->es_port); 596 597 AR40XX_UNLOCK(sc); 598 599 if (p->es_port == 0) { 600 /* CPU port */ 601 p->es_flags |= ETHERSWITCH_PORT_CPU; 602 ifmr = &p->es_ifmr; 603 ifmr->ifm_count = 0; 604 ifmr->ifm_current = ifmr->ifm_active = 605 IFM_ETHER | IFM_1000_T | IFM_FDX; 606 ifmr->ifm_mask = 0; 607 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 608 } else if (mii != NULL) { 609 /* non-CPU port */ 610 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 611 &mii->mii_media, SIOCGIFMEDIA); 612 if (err) 613 return (err); 614 } else { 615 return (ENXIO); 616 } 617 618 return (0); 619 } 620 621 /* 622 * Set the port configuration and status. 623 */ 624 static int 625 ar40xx_setport(device_t dev, etherswitch_port_t *p) 626 { 627 struct ar40xx_softc *sc = device_get_softc(dev); 628 struct ifmedia *ifm; 629 struct mii_data *mii; 630 struct ifnet *ifp; 631 int ret; 632 633 if (p->es_port < 0 || p->es_port > sc->sc_info.es_nports) 634 return (EINVAL); 635 636 /* Port flags */ 637 AR40XX_LOCK(sc); 638 ret = ar40xx_hw_set_port_pvid(sc, p->es_port, p->es_pvid); 639 if (ret != 0) { 640 AR40XX_UNLOCK(sc); 641 return (ret); 642 } 643 /* XXX TODO: tag strip/unstrip, double-tag, etc */ 644 AR40XX_UNLOCK(sc); 645 646 /* Don't change media config on CPU port */ 647 if (p->es_port == 0) 648 return (0); 649 650 mii = ar40xx_phy_miiforport(sc, p->es_port); 651 if (mii == NULL) 652 return (ENXIO); 653 654 ifp = ar40xx_phy_ifpforport(sc, p->es_port); 655 656 ifm = &mii->mii_media; 657 return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 658 659 return (0); 660 } 661 662 /* 663 * Get the current VLAN group (per-port, ISL, dot1q) configuration. 664 * 665 * For now the only supported operating mode is dot1q. 666 */ 667 static int 668 ar40xx_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 669 { 670 struct ar40xx_softc *sc = device_get_softc(dev); 671 int vid, ret; 672 673 if (vg->es_vlangroup > sc->sc_info.es_nvlangroups) 674 return (EINVAL); 675 676 vg->es_untagged_ports = 0; 677 vg->es_member_ports = 0; 678 vg->es_fid = 0; 679 680 AR40XX_LOCK(sc); 681 682 /* Note: only supporting 802.1q VLAN config for now */ 683 if (sc->sc_vlan.vlan != 1) { 684 vg->es_member_ports = 0; 685 vg->es_untagged_ports = 0; 686 AR40XX_UNLOCK(sc); 687 return (-1); 688 } 689 690 /* Get vlangroup mapping to VLAN id */ 691 vid = sc->sc_vlan.vlan_id[vg->es_vlangroup]; 692 if ((vid & ETHERSWITCH_VID_VALID) == 0) { 693 /* Not an active vgroup; bail */ 694 AR40XX_UNLOCK(sc); 695 return (0); 696 } 697 vg->es_vid = vid; 698 699 ret = ar40xx_hw_vtu_get_vlan(sc, vid, &vg->es_member_ports, 700 &vg->es_untagged_ports); 701 702 AR40XX_UNLOCK(sc); 703 704 if (ret == 0) { 705 vg->es_vid |= ETHERSWITCH_VID_VALID; 706 } 707 708 return (ret); 709 } 710 711 /* 712 * Set the current VLAN group (per-port, ISL, dot1q) configuration. 713 * 714 * For now the only supported operating mode is dot1q. 715 */ 716 static int 717 ar40xx_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 718 { 719 struct ar40xx_softc *sc = device_get_softc(dev); 720 int err, vid; 721 722 /* For now we only support 802.1q mode */ 723 if (sc->sc_vlan.vlan == 0) 724 return (EINVAL); 725 726 AR40XX_LOCK(sc); 727 vid = sc->sc_vlan.vlan_id[vg->es_vlangroup]; 728 /* 729 * If we have an 802.1q VID and it's different to the current one, 730 * purge the current VTU entry. 731 */ 732 if ((vid != 0) && 733 ((vid & ETHERSWITCH_VID_VALID) != 0) && 734 ((vid & ETHERSWITCH_VID_MASK) != 735 (vg->es_vid & ETHERSWITCH_VID_MASK))) { 736 AR40XX_DPRINTF(sc, AR40XX_DBG_VTU_OP, 737 "%s: purging VID %d first\n", __func__, vid); 738 err = ar40xx_hw_vtu_flush(sc); 739 if (err != 0) { 740 AR40XX_UNLOCK(sc); 741 return (err); 742 } 743 } 744 745 /* Update VLAN ID */ 746 vid = vg->es_vid & ETHERSWITCH_VID_MASK; 747 sc->sc_vlan.vlan_id[vg->es_vlangroup] = vid; 748 if (vid == 0) { 749 /* Setting it to 0 disables the group */ 750 AR40XX_UNLOCK(sc); 751 return (0); 752 } 753 /* Add valid bit for this entry */ 754 sc->sc_vlan.vlan_id[vg->es_vlangroup] = vid | ETHERSWITCH_VID_VALID; 755 756 /* Update hardware */ 757 err = ar40xx_hw_vtu_load_vlan(sc, vid, vg->es_member_ports, 758 vg->es_untagged_ports); 759 if (err != 0) { 760 AR40XX_UNLOCK(sc); 761 return (err); 762 } 763 764 /* Update the config for the given entry */ 765 sc->sc_vlan.vlan_ports[vg->es_vlangroup] = vg->es_member_ports; 766 sc->sc_vlan.vlan_untagged[vg->es_vlangroup] = vg->es_untagged_ports; 767 768 AR40XX_UNLOCK(sc); 769 770 return (0); 771 } 772 773 /* 774 * Get the current configuration mode. 775 */ 776 static int 777 ar40xx_getconf(device_t dev, etherswitch_conf_t *conf) 778 { 779 struct ar40xx_softc *sc = device_get_softc(dev); 780 int ret; 781 782 AR40XX_LOCK(sc); 783 784 /* Only support dot1q VLAN for now */ 785 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 786 conf->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 787 788 /* Switch MAC address */ 789 ret = ar40xx_hw_read_switch_mac_address(sc, &conf->switch_macaddr); 790 if (ret == 0) 791 conf->cmd |= ETHERSWITCH_CONF_SWITCH_MACADDR; 792 793 AR40XX_UNLOCK(sc); 794 795 return (0); 796 } 797 798 /* 799 * Set the current configuration and do a switch reset. 800 * 801 * For now the only supported operating mode is dot1q, don't 802 * allow it to be set to non-dot1q. 803 */ 804 static int 805 ar40xx_setconf(device_t dev, etherswitch_conf_t *conf) 806 { 807 struct ar40xx_softc *sc = device_get_softc(dev); 808 int ret = 0; 809 810 if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) { 811 /* Only support dot1q VLAN for now */ 812 if (conf->vlan_mode != ETHERSWITCH_VLAN_DOT1Q) 813 return (EINVAL); 814 } 815 816 if (conf->cmd & ETHERSWITCH_CONF_SWITCH_MACADDR) { 817 AR40XX_LOCK(sc); 818 ret = ar40xx_hw_read_switch_mac_address(sc, 819 &conf->switch_macaddr); 820 AR40XX_UNLOCK(sc); 821 } 822 823 return (ret); 824 } 825 826 /* 827 * Flush all ATU entries. 828 */ 829 static int 830 ar40xx_atu_flush_all(device_t dev) 831 { 832 struct ar40xx_softc *sc = device_get_softc(dev); 833 int ret; 834 835 AR40XX_LOCK(sc); 836 ret = ar40xx_hw_atu_flush_all(sc); 837 AR40XX_UNLOCK(sc); 838 return (ret); 839 } 840 841 /* 842 * Flush all ATU entries for the given port. 843 */ 844 static int 845 ar40xx_atu_flush_port(device_t dev, int port) 846 { 847 struct ar40xx_softc *sc = device_get_softc(dev); 848 int ret; 849 850 AR40XX_LOCK(sc); 851 ret = ar40xx_hw_atu_flush_port(sc, port); 852 AR40XX_UNLOCK(sc); 853 return (ret); 854 } 855 856 /* 857 * Load the ATU table into local storage so it can be iterated 858 * over. 859 */ 860 static int 861 ar40xx_atu_fetch_table(device_t dev, etherswitch_atu_table_t *table) 862 { 863 struct ar40xx_softc *sc = device_get_softc(dev); 864 int err, nitems; 865 866 memset(&sc->atu.entries, 0, sizeof(sc->atu.entries)); 867 868 table->es_nitems = 0; 869 nitems = 0; 870 871 AR40XX_LOCK(sc); 872 sc->atu.count = 0; 873 err = ar40xx_hw_atu_fetch_entry(sc, NULL, 0); 874 if (err != 0) 875 goto done; 876 877 while (nitems < AR40XX_NUM_ATU_ENTRIES) { 878 err = ar40xx_hw_atu_fetch_entry(sc, 879 &sc->atu.entries[nitems], 1); 880 if (err != 0) 881 goto done; 882 sc->atu.entries[nitems].id = nitems; 883 nitems++; 884 } 885 done: 886 sc->atu.count = nitems; 887 table->es_nitems = nitems; 888 AR40XX_UNLOCK(sc); 889 890 return (0); 891 } 892 893 /* 894 * Iterate over the ATU table entries that have been previously 895 * fetched. 896 */ 897 static int 898 ar40xx_atu_fetch_table_entry(device_t dev, etherswitch_atu_entry_t *e) 899 { 900 struct ar40xx_softc *sc = device_get_softc(dev); 901 int id, err = 0; 902 903 id = e->id; 904 AR40XX_LOCK(sc); 905 if (id > sc->atu.count) { 906 err = ENOENT; 907 goto done; 908 } 909 memcpy(e, &sc->atu.entries[id], sizeof(*e)); 910 done: 911 AR40XX_UNLOCK(sc); 912 return (err); 913 } 914 915 static device_method_t ar40xx_methods[] = { 916 /* Device interface */ 917 DEVMETHOD(device_probe, ar40xx_probe), 918 DEVMETHOD(device_attach, ar40xx_attach), 919 DEVMETHOD(device_detach, ar40xx_detach), 920 921 /* bus interface */ 922 DEVMETHOD(bus_add_child, device_add_child_ordered), 923 924 /* MII interface */ 925 DEVMETHOD(miibus_readreg, ar40xx_readphy), 926 DEVMETHOD(miibus_writereg, ar40xx_writephy), 927 DEVMETHOD(miibus_statchg, ar40xx_statchg), 928 929 /* MDIO interface */ 930 DEVMETHOD(mdio_readreg, ar40xx_readphy), 931 DEVMETHOD(mdio_writereg, ar40xx_writephy), 932 933 /* etherswitch interface */ 934 DEVMETHOD(etherswitch_lock, ar40xx_lock), 935 DEVMETHOD(etherswitch_unlock, ar40xx_unlock), 936 DEVMETHOD(etherswitch_getinfo, ar40xx_getinfo), 937 DEVMETHOD(etherswitch_readreg, ar40xx_readreg), 938 DEVMETHOD(etherswitch_writereg, ar40xx_writereg), 939 DEVMETHOD(etherswitch_readphyreg, ar40xx_readphy), 940 DEVMETHOD(etherswitch_writephyreg, ar40xx_writephy), 941 DEVMETHOD(etherswitch_getport, ar40xx_getport), 942 DEVMETHOD(etherswitch_setport, ar40xx_setport), 943 DEVMETHOD(etherswitch_getvgroup, ar40xx_getvgroup), 944 DEVMETHOD(etherswitch_setvgroup, ar40xx_setvgroup), 945 DEVMETHOD(etherswitch_getconf, ar40xx_getconf), 946 DEVMETHOD(etherswitch_setconf, ar40xx_setconf), 947 DEVMETHOD(etherswitch_flush_all, ar40xx_atu_flush_all), 948 DEVMETHOD(etherswitch_flush_port, ar40xx_atu_flush_port), 949 DEVMETHOD(etherswitch_fetch_table, ar40xx_atu_fetch_table), 950 DEVMETHOD(etherswitch_fetch_table_entry, 951 ar40xx_atu_fetch_table_entry), 952 953 DEVMETHOD_END 954 }; 955 956 DEFINE_CLASS_0(ar40xx, ar40xx_driver, ar40xx_methods, 957 sizeof(struct ar40xx_softc)); 958 959 DRIVER_MODULE(ar40xx, simplebus, ar40xx_driver, 0, 0); 960 DRIVER_MODULE(ar40xx, ofwbus, ar40xx_driver, 0, 0); 961 DRIVER_MODULE(miibus, ar40xx, miibus_driver, 0, 0); 962 DRIVER_MODULE(mdio, ar40xx, mdio_driver, 0, 0); 963 DRIVER_MODULE(etherswitch, ar40xx, etherswitch_driver, 0, 0); 964 MODULE_DEPEND(ar40xx, mdio, 1, 1, 1); 965 MODULE_DEPEND(ar40xx, miibus, 1, 1, 1); 966 MODULE_DEPEND(ar40xx, etherswitch, 1, 1, 1); 967 MODULE_VERSION(ar40xx, 1); 968