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