1b9f07b86SLuiz Otavio O Souza /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 4b9f07b86SLuiz Otavio O Souza * Copyright (c) 2013 Luiz Otavio O Souza. 5b9f07b86SLuiz Otavio O Souza * Copyright (c) 2011-2012 Stefan Bethke. 6b9f07b86SLuiz Otavio O Souza * Copyright (c) 2012 Adrian Chadd. 7b9f07b86SLuiz Otavio O Souza * All rights reserved. 8b9f07b86SLuiz Otavio O Souza * 9b9f07b86SLuiz Otavio O Souza * Redistribution and use in source and binary forms, with or without 10b9f07b86SLuiz Otavio O Souza * modification, are permitted provided that the following conditions 11b9f07b86SLuiz Otavio O Souza * are met: 12b9f07b86SLuiz Otavio O Souza * 1. Redistributions of source code must retain the above copyright 13b9f07b86SLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer. 14b9f07b86SLuiz Otavio O Souza * 2. Redistributions in binary form must reproduce the above copyright 15b9f07b86SLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer in the 16b9f07b86SLuiz Otavio O Souza * documentation and/or other materials provided with the distribution. 17b9f07b86SLuiz Otavio O Souza * 18b9f07b86SLuiz Otavio O Souza * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19b9f07b86SLuiz Otavio O Souza * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20b9f07b86SLuiz Otavio O Souza * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21b9f07b86SLuiz Otavio O Souza * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22b9f07b86SLuiz Otavio O Souza * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23b9f07b86SLuiz Otavio O Souza * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24b9f07b86SLuiz Otavio O Souza * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25b9f07b86SLuiz Otavio O Souza * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26b9f07b86SLuiz Otavio O Souza * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27b9f07b86SLuiz Otavio O Souza * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28b9f07b86SLuiz Otavio O Souza * SUCH DAMAGE. 29b9f07b86SLuiz Otavio O Souza * 30b9f07b86SLuiz Otavio O Souza * $FreeBSD$ 31b9f07b86SLuiz Otavio O Souza */ 32b9f07b86SLuiz Otavio O Souza 33b9f07b86SLuiz Otavio O Souza #include <sys/param.h> 34b9f07b86SLuiz Otavio O Souza #include <sys/bus.h> 35b9f07b86SLuiz Otavio O Souza #include <sys/errno.h> 36104dc214SGleb Smirnoff #include <sys/lock.h> 37b9f07b86SLuiz Otavio O Souza #include <sys/kernel.h> 38104dc214SGleb Smirnoff #include <sys/mutex.h> 39b9f07b86SLuiz Otavio O Souza #include <sys/systm.h> 40b9f07b86SLuiz Otavio O Souza #include <sys/socket.h> 41b9f07b86SLuiz Otavio O Souza 42b9f07b86SLuiz Otavio O Souza #include <net/if.h> 43b9f07b86SLuiz Otavio O Souza #include <dev/mii/mii.h> 44b9f07b86SLuiz Otavio O Souza 45b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/etherswitch.h> 46b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/arswitch/arswitchreg.h> 47b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/arswitch/arswitchvar.h> 48b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/arswitch/arswitch_reg.h> 49b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/arswitch/arswitch_vlans.h> 50b9f07b86SLuiz Otavio O Souza 51b9f07b86SLuiz Otavio O Souza #include "mdio_if.h" 52b9f07b86SLuiz Otavio O Souza #include "miibus_if.h" 53b9f07b86SLuiz Otavio O Souza #include "etherswitch_if.h" 54b9f07b86SLuiz Otavio O Souza 55db4ff7dbSAdrian Chadd /* 56db4ff7dbSAdrian Chadd * XXX TODO: teach about the AR934x SoC switch 57db4ff7dbSAdrian Chadd */ 58db4ff7dbSAdrian Chadd 59b9f07b86SLuiz Otavio O Souza static int 60f35f94f4SAdrian Chadd ar8xxx_vlan_op(struct arswitch_softc *sc, uint32_t op, uint32_t vid, 61b9f07b86SLuiz Otavio O Souza uint32_t data) 62b9f07b86SLuiz Otavio O Souza { 63b9f07b86SLuiz Otavio O Souza int err; 64b9f07b86SLuiz Otavio O Souza 65b9f07b86SLuiz Otavio O Souza if (arswitch_waitreg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, 66b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_ACTIVE, 0, 5)) 67b9f07b86SLuiz Otavio O Souza return (EBUSY); 68b9f07b86SLuiz Otavio O Souza 69b9f07b86SLuiz Otavio O Souza /* Load the vlan data if needed. */ 70b9f07b86SLuiz Otavio O Souza if (op == AR8X16_VLAN_OP_LOAD) { 71b9f07b86SLuiz Otavio O Souza err = arswitch_writereg(sc->sc_dev, AR8X16_REG_VLAN_DATA, 72b9f07b86SLuiz Otavio O Souza (data & AR8X16_VLAN_MEMBER) | AR8X16_VLAN_VALID); 73b9f07b86SLuiz Otavio O Souza if (err) 74b9f07b86SLuiz Otavio O Souza return (err); 75b9f07b86SLuiz Otavio O Souza } 76b9f07b86SLuiz Otavio O Souza 77b9f07b86SLuiz Otavio O Souza if (vid != 0) 78b9f07b86SLuiz Otavio O Souza op |= ((vid & ETHERSWITCH_VID_MASK) << AR8X16_VLAN_VID_SHIFT); 79b9f07b86SLuiz Otavio O Souza op |= AR8X16_VLAN_ACTIVE; 80b9f07b86SLuiz Otavio O Souza arswitch_writereg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, op); 81b9f07b86SLuiz Otavio O Souza 82b9f07b86SLuiz Otavio O Souza /* Wait for command processing. */ 83b9f07b86SLuiz Otavio O Souza if (arswitch_waitreg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, 84b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_ACTIVE, 0, 5)) 85b9f07b86SLuiz Otavio O Souza return (EBUSY); 86b9f07b86SLuiz Otavio O Souza 87b9f07b86SLuiz Otavio O Souza return (0); 88b9f07b86SLuiz Otavio O Souza } 89b9f07b86SLuiz Otavio O Souza 90f35f94f4SAdrian Chadd int 91f35f94f4SAdrian Chadd ar8xxx_flush_dot1q_vlan(struct arswitch_softc *sc) 92b9f07b86SLuiz Otavio O Souza { 93b9f07b86SLuiz Otavio O Souza 94b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 95f35f94f4SAdrian Chadd return (ar8xxx_vlan_op(sc, AR8X16_VLAN_OP_FLUSH, 0, 0)); 96b9f07b86SLuiz Otavio O Souza } 97b9f07b86SLuiz Otavio O Souza 98f35f94f4SAdrian Chadd int 99f35f94f4SAdrian Chadd ar8xxx_purge_dot1q_vlan(struct arswitch_softc *sc, int vid) 100b9f07b86SLuiz Otavio O Souza { 101b9f07b86SLuiz Otavio O Souza 102b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 103f35f94f4SAdrian Chadd return (ar8xxx_vlan_op(sc, AR8X16_VLAN_OP_PURGE, vid, 0)); 104b9f07b86SLuiz Otavio O Souza } 105b9f07b86SLuiz Otavio O Souza 106749cac13SAdrian Chadd int 107036e1c76SAdrian Chadd ar8xxx_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, 108036e1c76SAdrian Chadd uint32_t *untagged_ports, int vid) 109b9f07b86SLuiz Otavio O Souza { 110b9f07b86SLuiz Otavio O Souza uint32_t reg; 111b9f07b86SLuiz Otavio O Souza int err; 112b9f07b86SLuiz Otavio O Souza 113b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 114f35f94f4SAdrian Chadd err = ar8xxx_vlan_op(sc, AR8X16_VLAN_OP_GET, vid, 0); 115b9f07b86SLuiz Otavio O Souza if (err) 116b9f07b86SLuiz Otavio O Souza return (err); 117b9f07b86SLuiz Otavio O Souza 118b9f07b86SLuiz Otavio O Souza reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_VLAN_DATA); 119b9f07b86SLuiz Otavio O Souza if ((reg & AR8X16_VLAN_VALID) == 0) { 120b9f07b86SLuiz Otavio O Souza *ports = 0; 121b9f07b86SLuiz Otavio O Souza return (EINVAL); 122b9f07b86SLuiz Otavio O Souza } 123b9f07b86SLuiz Otavio O Souza reg &= ((1 << (sc->numphys + 1)) - 1); 124b9f07b86SLuiz Otavio O Souza *ports = reg; 125036e1c76SAdrian Chadd *untagged_ports = reg; 126b9f07b86SLuiz Otavio O Souza return (0); 127b9f07b86SLuiz Otavio O Souza } 128b9f07b86SLuiz Otavio O Souza 129749cac13SAdrian Chadd int 130036e1c76SAdrian Chadd ar8xxx_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, 131036e1c76SAdrian Chadd uint32_t untagged_ports, int vid) 132b9f07b86SLuiz Otavio O Souza { 133b9f07b86SLuiz Otavio O Souza int err; 134b9f07b86SLuiz Otavio O Souza 135b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 136f35f94f4SAdrian Chadd err = ar8xxx_vlan_op(sc, AR8X16_VLAN_OP_LOAD, vid, ports); 137b9f07b86SLuiz Otavio O Souza if (err) 138b9f07b86SLuiz Otavio O Souza return (err); 139b9f07b86SLuiz Otavio O Souza return (0); 140b9f07b86SLuiz Otavio O Souza } 141b9f07b86SLuiz Otavio O Souza 142749cac13SAdrian Chadd int 143749cac13SAdrian Chadd ar8xxx_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid) 144b9f07b86SLuiz Otavio O Souza { 145b9f07b86SLuiz Otavio O Souza int port; 146b9f07b86SLuiz Otavio O Souza uint32_t reg; 147b9f07b86SLuiz Otavio O Souza 148b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 149b9f07b86SLuiz Otavio O Souza /* For port based vlans the vlanid is the same as the port index. */ 150b9f07b86SLuiz Otavio O Souza port = vid & ETHERSWITCH_VID_MASK; 151b9f07b86SLuiz Otavio O Souza reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port)); 152b9f07b86SLuiz Otavio O Souza *ports = (reg >> AR8X16_PORT_VLAN_DEST_PORTS_SHIFT); 153b9f07b86SLuiz Otavio O Souza *ports &= AR8X16_VLAN_MEMBER; 154b9f07b86SLuiz Otavio O Souza return (0); 155b9f07b86SLuiz Otavio O Souza } 156b9f07b86SLuiz Otavio O Souza 157749cac13SAdrian Chadd int 158749cac13SAdrian Chadd ar8xxx_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid) 159b9f07b86SLuiz Otavio O Souza { 160b9f07b86SLuiz Otavio O Souza int err, port; 161b9f07b86SLuiz Otavio O Souza 162b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 163b9f07b86SLuiz Otavio O Souza /* For port based vlans the vlanid is the same as the port index. */ 164b9f07b86SLuiz Otavio O Souza port = vid & ETHERSWITCH_VID_MASK; 165b9f07b86SLuiz Otavio O Souza err = arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port), 166b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_MEMBER << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 167b9f07b86SLuiz Otavio O Souza (ports & AR8X16_VLAN_MEMBER) << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT); 168b9f07b86SLuiz Otavio O Souza if (err) 169b9f07b86SLuiz Otavio O Souza return (err); 170b9f07b86SLuiz Otavio O Souza return (0); 171b9f07b86SLuiz Otavio O Souza } 172b9f07b86SLuiz Otavio O Souza 173b9f07b86SLuiz Otavio O Souza /* 174b9f07b86SLuiz Otavio O Souza * Reset vlans to default state. 175b9f07b86SLuiz Otavio O Souza */ 176b9f07b86SLuiz Otavio O Souza void 1776dcbabd7SAdrian Chadd ar8xxx_reset_vlans(struct arswitch_softc *sc) 178b9f07b86SLuiz Otavio O Souza { 179b9f07b86SLuiz Otavio O Souza uint32_t ports; 180b9f07b86SLuiz Otavio O Souza int i, j; 181b9f07b86SLuiz Otavio O Souza 182b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 183b9f07b86SLuiz Otavio O Souza 184b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK(sc); 185b9f07b86SLuiz Otavio O Souza 186b9f07b86SLuiz Otavio O Souza /* Reset all vlan data. */ 187b9f07b86SLuiz Otavio O Souza memset(sc->vid, 0, sizeof(sc->vid)); 188b9f07b86SLuiz Otavio O Souza 189b9f07b86SLuiz Otavio O Souza /* Disable the QinQ and egress filters for all ports. */ 190b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) { 191b9f07b86SLuiz Otavio O Souza if (arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(i), 192b9f07b86SLuiz Otavio O Souza 0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT | 193b9f07b86SLuiz Otavio O Souza AR8X16_PORT_CTRL_DOUBLE_TAG, 0)) { 194b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 195b9f07b86SLuiz Otavio O Souza return; 196b9f07b86SLuiz Otavio O Souza } 197b9f07b86SLuiz Otavio O Souza } 198b9f07b86SLuiz Otavio O Souza 199f35f94f4SAdrian Chadd if (sc->hal.arswitch_flush_dot1q_vlan(sc)) { 200b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 201b9f07b86SLuiz Otavio O Souza return; 202b9f07b86SLuiz Otavio O Souza } 203b9f07b86SLuiz Otavio O Souza 204b9f07b86SLuiz Otavio O Souza if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 205b9f07b86SLuiz Otavio O Souza /* 206b9f07b86SLuiz Otavio O Souza * Reset the port based vlan settings and turn on the 207b9f07b86SLuiz Otavio O Souza * ingress filter for all ports. 208b9f07b86SLuiz Otavio O Souza */ 209b9f07b86SLuiz Otavio O Souza ports = 0; 210b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) 211b9f07b86SLuiz Otavio O Souza arswitch_modifyreg(sc->sc_dev, 212b9f07b86SLuiz Otavio O Souza AR8X16_REG_PORT_VLAN(i), 213b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_MASK | 214b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_MEMBER << 215b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 216b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_SECURE << 217b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_SHIFT); 218b9f07b86SLuiz Otavio O Souza 219b9f07b86SLuiz Otavio O Souza /* 220b9f07b86SLuiz Otavio O Souza * Setup vlan 1 as PVID for all switch ports. Add all ports 221b9f07b86SLuiz Otavio O Souza * as members of vlan 1. 222b9f07b86SLuiz Otavio O Souza */ 223b9f07b86SLuiz Otavio O Souza sc->vid[0] = 1; 224b9f07b86SLuiz Otavio O Souza /* Set PVID for everyone. */ 225b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) 2266dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_set_pvid(sc, i, sc->vid[0]); 227b9f07b86SLuiz Otavio O Souza ports = 0; 228b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) 229b9f07b86SLuiz Otavio O Souza ports |= (1 << i); 230036e1c76SAdrian Chadd sc->hal.arswitch_set_dot1q_vlan(sc, ports, sc->vid[0], sc->vid[0]); 231b9f07b86SLuiz Otavio O Souza sc->vid[0] |= ETHERSWITCH_VID_VALID; 232b9f07b86SLuiz Otavio O Souza } else if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 233b9f07b86SLuiz Otavio O Souza /* Initialize the port based vlans. */ 234b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) { 235b9f07b86SLuiz Otavio O Souza sc->vid[i] = i | ETHERSWITCH_VID_VALID; 236b9f07b86SLuiz Otavio O Souza ports = 0; 237b9f07b86SLuiz Otavio O Souza for (j = 0; j <= sc->numphys; j++) 238b9f07b86SLuiz Otavio O Souza ports |= (1 << j); 239b9f07b86SLuiz Otavio O Souza arswitch_modifyreg(sc->sc_dev, 240b9f07b86SLuiz Otavio O Souza AR8X16_REG_PORT_VLAN(i), 241b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_MASK | 242b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_MEMBER << 243b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 244b9f07b86SLuiz Otavio O Souza ports << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT | 245b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_SECURE << 246b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_PORT_ONLY); 247036e1c76SAdrian Chadd /* XXX TODO: SECURE / PORT_ONLY is wrong? */ 248b9f07b86SLuiz Otavio O Souza } 249b9f07b86SLuiz Otavio O Souza } else { 250b9f07b86SLuiz Otavio O Souza /* Disable the ingress filter and get everyone on all vlans. */ 251b9f07b86SLuiz Otavio O Souza for (i = 0; i <= sc->numphys; i++) 252b9f07b86SLuiz Otavio O Souza arswitch_modifyreg(sc->sc_dev, 253b9f07b86SLuiz Otavio O Souza AR8X16_REG_PORT_VLAN(i), 254b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_MASK | 255b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_MEMBER << 256b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 257b9f07b86SLuiz Otavio O Souza AR8X16_VLAN_MEMBER << 258b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_DEST_PORTS_SHIFT | 259b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_SECURE << 260b9f07b86SLuiz Otavio O Souza AR8X16_PORT_VLAN_MODE_PORT_ONLY); 261b9f07b86SLuiz Otavio O Souza } 262b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 263b9f07b86SLuiz Otavio O Souza } 264b9f07b86SLuiz Otavio O Souza 265b9f07b86SLuiz Otavio O Souza int 2666dcbabd7SAdrian Chadd ar8xxx_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 267b9f07b86SLuiz Otavio O Souza { 268b9f07b86SLuiz Otavio O Souza int err; 269b9f07b86SLuiz Otavio O Souza 270b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 271b9f07b86SLuiz Otavio O Souza 272b9f07b86SLuiz Otavio O Souza if (vg->es_vlangroup > sc->info.es_nvlangroups) 273b9f07b86SLuiz Otavio O Souza return (EINVAL); 274b9f07b86SLuiz Otavio O Souza 275b9f07b86SLuiz Otavio O Souza /* Reset the members ports. */ 276b9f07b86SLuiz Otavio O Souza vg->es_untagged_ports = 0; 277b9f07b86SLuiz Otavio O Souza vg->es_member_ports = 0; 278b9f07b86SLuiz Otavio O Souza 279b9f07b86SLuiz Otavio O Souza /* Not supported. */ 280b9f07b86SLuiz Otavio O Souza vg->es_fid = 0; 281b9f07b86SLuiz Otavio O Souza 282b9f07b86SLuiz Otavio O Souza /* Vlan ID. */ 283b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK(sc); 284b9f07b86SLuiz Otavio O Souza vg->es_vid = sc->vid[vg->es_vlangroup]; 285b9f07b86SLuiz Otavio O Souza if ((vg->es_vid & ETHERSWITCH_VID_VALID) == 0) { 286b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 287b9f07b86SLuiz Otavio O Souza return (0); 288b9f07b86SLuiz Otavio O Souza } 289b9f07b86SLuiz Otavio O Souza 290b9f07b86SLuiz Otavio O Souza /* Member Ports. */ 291b9f07b86SLuiz Otavio O Souza switch (sc->vlan_mode) { 292b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_DOT1Q: 293749cac13SAdrian Chadd err = sc->hal.arswitch_get_dot1q_vlan(sc, &vg->es_member_ports, 294036e1c76SAdrian Chadd &vg->es_untagged_ports, 295b9f07b86SLuiz Otavio O Souza vg->es_vid); 296b9f07b86SLuiz Otavio O Souza break; 297b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_PORT: 298749cac13SAdrian Chadd err = sc->hal.arswitch_get_port_vlan(sc, &vg->es_member_ports, 299b9f07b86SLuiz Otavio O Souza vg->es_vid); 300036e1c76SAdrian Chadd vg->es_untagged_ports = vg->es_member_ports; 301b9f07b86SLuiz Otavio O Souza break; 302b9f07b86SLuiz Otavio O Souza default: 303b9f07b86SLuiz Otavio O Souza vg->es_member_ports = 0; 304036e1c76SAdrian Chadd vg->es_untagged_ports = 0; 305b9f07b86SLuiz Otavio O Souza err = -1; 306b9f07b86SLuiz Otavio O Souza } 307b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 308036e1c76SAdrian Chadd 309b9f07b86SLuiz Otavio O Souza return (err); 310b9f07b86SLuiz Otavio O Souza } 311b9f07b86SLuiz Otavio O Souza 312b9f07b86SLuiz Otavio O Souza int 3136dcbabd7SAdrian Chadd ar8xxx_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 314b9f07b86SLuiz Otavio O Souza { 315b9f07b86SLuiz Otavio O Souza int err, vid; 316b9f07b86SLuiz Otavio O Souza 317b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 318b9f07b86SLuiz Otavio O Souza 319b9f07b86SLuiz Otavio O Souza /* Check VLAN mode. */ 320b9f07b86SLuiz Otavio O Souza if (sc->vlan_mode == 0) 321b9f07b86SLuiz Otavio O Souza return (EINVAL); 322b9f07b86SLuiz Otavio O Souza 323b9f07b86SLuiz Otavio O Souza /* 324b9f07b86SLuiz Otavio O Souza * Check if we are changing the vlanid for an already used vtu entry. 325b9f07b86SLuiz Otavio O Souza * Then purge the entry first. 326b9f07b86SLuiz Otavio O Souza */ 327b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK(sc); 328b9f07b86SLuiz Otavio O Souza vid = sc->vid[vg->es_vlangroup]; 329b9f07b86SLuiz Otavio O Souza if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q && 330b9f07b86SLuiz Otavio O Souza (vid & ETHERSWITCH_VID_VALID) != 0 && 331b9f07b86SLuiz Otavio O Souza (vid & ETHERSWITCH_VID_MASK) != 332b9f07b86SLuiz Otavio O Souza (vg->es_vid & ETHERSWITCH_VID_MASK)) { 333f35f94f4SAdrian Chadd err = sc->hal.arswitch_purge_dot1q_vlan(sc, vid); 334b9f07b86SLuiz Otavio O Souza if (err) { 335b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 336b9f07b86SLuiz Otavio O Souza return (err); 337b9f07b86SLuiz Otavio O Souza } 338b9f07b86SLuiz Otavio O Souza } 339b9f07b86SLuiz Otavio O Souza 340b9f07b86SLuiz Otavio O Souza /* Vlan ID. */ 341b9f07b86SLuiz Otavio O Souza if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 342b9f07b86SLuiz Otavio O Souza sc->vid[vg->es_vlangroup] = vg->es_vid & ETHERSWITCH_VID_MASK; 343b9f07b86SLuiz Otavio O Souza /* Setting the vlanid to zero disables the vlangroup. */ 344b9f07b86SLuiz Otavio O Souza if (sc->vid[vg->es_vlangroup] == 0) { 345b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 346b9f07b86SLuiz Otavio O Souza return (0); 347b9f07b86SLuiz Otavio O Souza } 348b9f07b86SLuiz Otavio O Souza sc->vid[vg->es_vlangroup] |= ETHERSWITCH_VID_VALID; 349b9f07b86SLuiz Otavio O Souza vid = sc->vid[vg->es_vlangroup]; 350b9f07b86SLuiz Otavio O Souza } 351b9f07b86SLuiz Otavio O Souza 352b9f07b86SLuiz Otavio O Souza /* Member Ports. */ 353b9f07b86SLuiz Otavio O Souza switch (sc->vlan_mode) { 354b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_DOT1Q: 355036e1c76SAdrian Chadd err = sc->hal.arswitch_set_dot1q_vlan(sc, vg->es_member_ports, 356036e1c76SAdrian Chadd vg->es_untagged_ports, vid); 357b9f07b86SLuiz Otavio O Souza break; 358b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_PORT: 359749cac13SAdrian Chadd err = sc->hal.arswitch_set_port_vlan(sc, vg->es_member_ports, vid); 360b9f07b86SLuiz Otavio O Souza break; 361b9f07b86SLuiz Otavio O Souza default: 362b9f07b86SLuiz Otavio O Souza err = -1; 363b9f07b86SLuiz Otavio O Souza } 364b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 365b9f07b86SLuiz Otavio O Souza return (err); 366b9f07b86SLuiz Otavio O Souza } 367b9f07b86SLuiz Otavio O Souza 368b9f07b86SLuiz Otavio O Souza int 3696dcbabd7SAdrian Chadd ar8xxx_get_pvid(struct arswitch_softc *sc, int port, int *pvid) 370b9f07b86SLuiz Otavio O Souza { 371b9f07b86SLuiz Otavio O Souza uint32_t reg; 372b9f07b86SLuiz Otavio O Souza 373b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 374b9f07b86SLuiz Otavio O Souza reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port)); 375b9f07b86SLuiz Otavio O Souza *pvid = reg & 0xfff; 376b9f07b86SLuiz Otavio O Souza return (0); 377b9f07b86SLuiz Otavio O Souza } 378b9f07b86SLuiz Otavio O Souza 379b9f07b86SLuiz Otavio O Souza int 3806dcbabd7SAdrian Chadd ar8xxx_set_pvid(struct arswitch_softc *sc, int port, int pvid) 381b9f07b86SLuiz Otavio O Souza { 382b9f07b86SLuiz Otavio O Souza 383b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 384b9f07b86SLuiz Otavio O Souza return (arswitch_modifyreg(sc->sc_dev, 385b9f07b86SLuiz Otavio O Souza AR8X16_REG_PORT_VLAN(port), 0xfff, pvid)); 386b9f07b86SLuiz Otavio O Souza } 387