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/kernel.h> 35 #include <sys/systm.h> 36 #include <sys/socket.h> 37 38 #include <net/if.h> 39 40 #include <dev/mii/mii.h> 41 42 #include <dev/etherswitch/etherswitch.h> 43 #include <dev/etherswitch/arswitch/arswitchreg.h> 44 #include <dev/etherswitch/arswitch/arswitchvar.h> 45 #include <dev/etherswitch/arswitch/arswitch_reg.h> 46 #include <dev/etherswitch/arswitch/arswitch_vlans.h> 47 48 #include "mdio_if.h" 49 #include "miibus_if.h" 50 #include "etherswitch_if.h" 51 52 static int 53 arswitch_vlan_op(struct arswitch_softc *sc, uint32_t op, uint32_t vid, 54 uint32_t data) 55 { 56 int err; 57 58 if (arswitch_waitreg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, 59 AR8X16_VLAN_ACTIVE, 0, 5)) 60 return (EBUSY); 61 62 /* Load the vlan data if needed. */ 63 if (op == AR8X16_VLAN_OP_LOAD) { 64 err = arswitch_writereg(sc->sc_dev, AR8X16_REG_VLAN_DATA, 65 (data & AR8X16_VLAN_MEMBER) | AR8X16_VLAN_VALID); 66 if (err) 67 return (err); 68 } 69 70 if (vid != 0) 71 op |= ((vid & ETHERSWITCH_VID_MASK) << AR8X16_VLAN_VID_SHIFT); 72 op |= AR8X16_VLAN_ACTIVE; 73 arswitch_writereg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, op); 74 75 /* Wait for command processing. */ 76 if (arswitch_waitreg(sc->sc_dev, AR8X16_REG_VLAN_CTRL, 77 AR8X16_VLAN_ACTIVE, 0, 5)) 78 return (EBUSY); 79 80 return (0); 81 } 82 83 static int 84 arswitch_flush_dot1q_vlan(struct arswitch_softc *sc) 85 { 86 87 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 88 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_FLUSH, 0, 0)); 89 } 90 91 static int 92 arswitch_purge_dot1q_vlan(struct arswitch_softc *sc, int vid) 93 { 94 95 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 96 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_PURGE, vid, 0)); 97 } 98 99 static int 100 arswitch_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid) 101 { 102 uint32_t reg; 103 int err; 104 105 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 106 err = arswitch_vlan_op(sc, AR8X16_VLAN_OP_GET, vid, 0); 107 if (err) 108 return (err); 109 110 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_VLAN_DATA); 111 if ((reg & AR8X16_VLAN_VALID) == 0) { 112 *ports = 0; 113 return (EINVAL); 114 } 115 reg &= ((1 << (sc->numphys + 1)) - 1); 116 *ports = reg; 117 return (0); 118 } 119 120 static int 121 arswitch_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid) 122 { 123 int err; 124 125 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 126 err = arswitch_vlan_op(sc, AR8X16_VLAN_OP_LOAD, vid, ports); 127 if (err) 128 return (err); 129 return (0); 130 } 131 132 static int 133 arswitch_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid) 134 { 135 int port; 136 uint32_t reg; 137 138 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 139 /* For port based vlans the vlanid is the same as the port index. */ 140 port = vid & ETHERSWITCH_VID_MASK; 141 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port)); 142 *ports = (reg >> AR8X16_PORT_VLAN_DEST_PORTS_SHIFT); 143 *ports &= AR8X16_VLAN_MEMBER; 144 return (0); 145 } 146 147 static int 148 arswitch_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid) 149 { 150 int err, port; 151 152 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 153 /* For port based vlans the vlanid is the same as the port index. */ 154 port = vid & ETHERSWITCH_VID_MASK; 155 err = arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port), 156 AR8X16_VLAN_MEMBER << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 157 (ports & AR8X16_VLAN_MEMBER) << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT); 158 if (err) 159 return (err); 160 return (0); 161 } 162 163 /* 164 * Reset vlans to default state. 165 */ 166 void 167 arswitch_reset_vlans(struct arswitch_softc *sc) 168 { 169 uint32_t ports; 170 int i, j; 171 172 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 173 174 ARSWITCH_LOCK(sc); 175 176 /* Reset all vlan data. */ 177 memset(sc->vid, 0, sizeof(sc->vid)); 178 179 /* Disable the QinQ and egress filters for all ports. */ 180 for (i = 0; i <= sc->numphys; i++) { 181 if (arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(i), 182 0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT | 183 AR8X16_PORT_CTRL_DOUBLE_TAG, 0)) { 184 ARSWITCH_UNLOCK(sc); 185 return; 186 } 187 } 188 189 if (arswitch_flush_dot1q_vlan(sc)) { 190 ARSWITCH_UNLOCK(sc); 191 return; 192 } 193 194 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 195 /* 196 * Reset the port based vlan settings and turn on the 197 * ingress filter for all ports. 198 */ 199 ports = 0; 200 for (i = 0; i <= sc->numphys; i++) 201 arswitch_modifyreg(sc->sc_dev, 202 AR8X16_REG_PORT_VLAN(i), 203 AR8X16_PORT_VLAN_MODE_MASK | 204 AR8X16_VLAN_MEMBER << 205 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 206 AR8X16_PORT_VLAN_MODE_SECURE << 207 AR8X16_PORT_VLAN_MODE_SHIFT); 208 209 /* 210 * Setup vlan 1 as PVID for all switch ports. Add all ports 211 * as members of vlan 1. 212 */ 213 sc->vid[0] = 1; 214 /* Set PVID for everyone. */ 215 for (i = 0; i <= sc->numphys; i++) 216 arswitch_set_pvid(sc, i, sc->vid[0]); 217 ports = 0; 218 for (i = 0; i <= sc->numphys; i++) 219 ports |= (1 << i); 220 arswitch_set_dot1q_vlan(sc, ports, sc->vid[0]); 221 sc->vid[0] |= ETHERSWITCH_VID_VALID; 222 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 223 /* Initialize the port based vlans. */ 224 for (i = 0; i <= sc->numphys; i++) { 225 sc->vid[i] = i | ETHERSWITCH_VID_VALID; 226 ports = 0; 227 for (j = 0; j <= sc->numphys; j++) 228 ports |= (1 << j); 229 arswitch_modifyreg(sc->sc_dev, 230 AR8X16_REG_PORT_VLAN(i), 231 AR8X16_PORT_VLAN_MODE_MASK | 232 AR8X16_VLAN_MEMBER << 233 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 234 ports << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT | 235 AR8X16_PORT_VLAN_MODE_SECURE << 236 AR8X16_PORT_VLAN_MODE_PORT_ONLY); 237 } 238 } else { 239 /* Disable the ingress filter and get everyone on all vlans. */ 240 for (i = 0; i <= sc->numphys; i++) 241 arswitch_modifyreg(sc->sc_dev, 242 AR8X16_REG_PORT_VLAN(i), 243 AR8X16_PORT_VLAN_MODE_MASK | 244 AR8X16_VLAN_MEMBER << 245 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT, 246 AR8X16_VLAN_MEMBER << 247 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT | 248 AR8X16_PORT_VLAN_MODE_SECURE << 249 AR8X16_PORT_VLAN_MODE_PORT_ONLY); 250 } 251 ARSWITCH_UNLOCK(sc); 252 } 253 254 int 255 arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 256 { 257 struct arswitch_softc *sc; 258 int err; 259 260 sc = device_get_softc(dev); 261 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 262 263 if (vg->es_vlangroup > sc->info.es_nvlangroups) 264 return (EINVAL); 265 266 /* Reset the members ports. */ 267 vg->es_untagged_ports = 0; 268 vg->es_member_ports = 0; 269 270 /* Not supported. */ 271 vg->es_fid = 0; 272 273 /* Vlan ID. */ 274 ARSWITCH_LOCK(sc); 275 vg->es_vid = sc->vid[vg->es_vlangroup]; 276 if ((vg->es_vid & ETHERSWITCH_VID_VALID) == 0) { 277 ARSWITCH_UNLOCK(sc); 278 return (0); 279 } 280 281 /* Member Ports. */ 282 switch (sc->vlan_mode) { 283 case ETHERSWITCH_VLAN_DOT1Q: 284 err = arswitch_get_dot1q_vlan(sc, &vg->es_member_ports, 285 vg->es_vid); 286 break; 287 case ETHERSWITCH_VLAN_PORT: 288 err = arswitch_get_port_vlan(sc, &vg->es_member_ports, 289 vg->es_vid); 290 break; 291 default: 292 vg->es_member_ports = 0; 293 err = -1; 294 } 295 ARSWITCH_UNLOCK(sc); 296 vg->es_untagged_ports = vg->es_member_ports; 297 return (err); 298 } 299 300 int 301 arswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 302 { 303 struct arswitch_softc *sc; 304 int err, vid; 305 306 sc = device_get_softc(dev); 307 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 308 309 /* Check VLAN mode. */ 310 if (sc->vlan_mode == 0) 311 return (EINVAL); 312 313 /* 314 * Check if we are changing the vlanid for an already used vtu entry. 315 * Then purge the entry first. 316 */ 317 ARSWITCH_LOCK(sc); 318 vid = sc->vid[vg->es_vlangroup]; 319 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q && 320 (vid & ETHERSWITCH_VID_VALID) != 0 && 321 (vid & ETHERSWITCH_VID_MASK) != 322 (vg->es_vid & ETHERSWITCH_VID_MASK)) { 323 err = arswitch_purge_dot1q_vlan(sc, vid); 324 if (err) { 325 ARSWITCH_UNLOCK(sc); 326 return (err); 327 } 328 } 329 330 /* Vlan ID. */ 331 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 332 sc->vid[vg->es_vlangroup] = vg->es_vid & ETHERSWITCH_VID_MASK; 333 /* Setting the vlanid to zero disables the vlangroup. */ 334 if (sc->vid[vg->es_vlangroup] == 0) { 335 ARSWITCH_UNLOCK(sc); 336 return (0); 337 } 338 sc->vid[vg->es_vlangroup] |= ETHERSWITCH_VID_VALID; 339 vid = sc->vid[vg->es_vlangroup]; 340 } 341 342 /* Member Ports. */ 343 switch (sc->vlan_mode) { 344 case ETHERSWITCH_VLAN_DOT1Q: 345 err = arswitch_set_dot1q_vlan(sc, vg->es_member_ports, vid); 346 break; 347 case ETHERSWITCH_VLAN_PORT: 348 err = arswitch_set_port_vlan(sc, vg->es_member_ports, vid); 349 break; 350 default: 351 err = -1; 352 } 353 ARSWITCH_UNLOCK(sc); 354 return (err); 355 } 356 357 int 358 arswitch_get_pvid(struct arswitch_softc *sc, int port, int *pvid) 359 { 360 uint32_t reg; 361 362 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 363 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port)); 364 *pvid = reg & 0xfff; 365 return (0); 366 } 367 368 int 369 arswitch_set_pvid(struct arswitch_softc *sc, int port, int pvid) 370 { 371 372 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 373 return (arswitch_modifyreg(sc->sc_dev, 374 AR8X16_REG_PORT_VLAN(port), 0xfff, pvid)); 375 } 376