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