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