Deleted Added
full compact
arswitch_vlans.c (257284) arswitch_vlans.c (262429)
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 *
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: head/sys/dev/etherswitch/arswitch/arswitch_vlans.c 257284 2013-10-28 22:26:03Z glebius $
28 * $FreeBSD: head/sys/dev/etherswitch/arswitch/arswitch_vlans.c 262429 2014-02-24 04:44:28Z adrian $
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 * XXX TODO: teach about the AR8327 external switch
57 */
58
59static int
60arswitch_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
90static int
91arswitch_flush_dot1q_vlan(struct arswitch_softc *sc)
92{
93
94 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
95 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_FLUSH, 0, 0));
96}
97
98static int
99arswitch_purge_dot1q_vlan(struct arswitch_softc *sc, int vid)
100{
101
102 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
103 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_PURGE, vid, 0));
104}
105
106static int
107arswitch_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
108{
109 uint32_t reg;
110 int err;
111
112 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
113 err = arswitch_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 return (0);
125}
126
127static int
128arswitch_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
129{
130 int err;
131
132 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
133 err = arswitch_vlan_op(sc, AR8X16_VLAN_OP_LOAD, vid, ports);
134 if (err)
135 return (err);
136 return (0);
137}
138
139static int
140arswitch_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
141{
142 int port;
143 uint32_t reg;
144
145 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
146 /* For port based vlans the vlanid is the same as the port index. */
147 port = vid & ETHERSWITCH_VID_MASK;
148 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port));
149 *ports = (reg >> AR8X16_PORT_VLAN_DEST_PORTS_SHIFT);
150 *ports &= AR8X16_VLAN_MEMBER;
151 return (0);
152}
153
154static int
155arswitch_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
156{
157 int err, port;
158
159 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
160 /* For port based vlans the vlanid is the same as the port index. */
161 port = vid & ETHERSWITCH_VID_MASK;
162 err = arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port),
163 AR8X16_VLAN_MEMBER << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
164 (ports & AR8X16_VLAN_MEMBER) << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT);
165 if (err)
166 return (err);
167 return (0);
168}
169
170/*
171 * Reset vlans to default state.
172 */
173void
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 * XXX TODO: teach about the AR8327 external switch
57 */
58
59static int
60arswitch_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
90static int
91arswitch_flush_dot1q_vlan(struct arswitch_softc *sc)
92{
93
94 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
95 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_FLUSH, 0, 0));
96}
97
98static int
99arswitch_purge_dot1q_vlan(struct arswitch_softc *sc, int vid)
100{
101
102 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
103 return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_PURGE, vid, 0));
104}
105
106static int
107arswitch_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
108{
109 uint32_t reg;
110 int err;
111
112 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
113 err = arswitch_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 return (0);
125}
126
127static int
128arswitch_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
129{
130 int err;
131
132 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
133 err = arswitch_vlan_op(sc, AR8X16_VLAN_OP_LOAD, vid, ports);
134 if (err)
135 return (err);
136 return (0);
137}
138
139static int
140arswitch_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
141{
142 int port;
143 uint32_t reg;
144
145 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
146 /* For port based vlans the vlanid is the same as the port index. */
147 port = vid & ETHERSWITCH_VID_MASK;
148 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port));
149 *ports = (reg >> AR8X16_PORT_VLAN_DEST_PORTS_SHIFT);
150 *ports &= AR8X16_VLAN_MEMBER;
151 return (0);
152}
153
154static int
155arswitch_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
156{
157 int err, port;
158
159 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
160 /* For port based vlans the vlanid is the same as the port index. */
161 port = vid & ETHERSWITCH_VID_MASK;
162 err = arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port),
163 AR8X16_VLAN_MEMBER << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
164 (ports & AR8X16_VLAN_MEMBER) << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT);
165 if (err)
166 return (err);
167 return (0);
168}
169
170/*
171 * Reset vlans to default state.
172 */
173void
174arswitch_reset_vlans(struct arswitch_softc *sc)
174ar8xxx_reset_vlans(struct arswitch_softc *sc)
175{
176 uint32_t ports;
177 int i, j;
178
179 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
180
181 ARSWITCH_LOCK(sc);
182
183 /* Reset all vlan data. */
184 memset(sc->vid, 0, sizeof(sc->vid));
185
186 /* Disable the QinQ and egress filters for all ports. */
187 for (i = 0; i <= sc->numphys; i++) {
188 if (arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(i),
189 0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT |
190 AR8X16_PORT_CTRL_DOUBLE_TAG, 0)) {
191 ARSWITCH_UNLOCK(sc);
192 return;
193 }
194 }
195
196 if (arswitch_flush_dot1q_vlan(sc)) {
197 ARSWITCH_UNLOCK(sc);
198 return;
199 }
200
201 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
202 /*
203 * Reset the port based vlan settings and turn on the
204 * ingress filter for all ports.
205 */
206 ports = 0;
207 for (i = 0; i <= sc->numphys; i++)
208 arswitch_modifyreg(sc->sc_dev,
209 AR8X16_REG_PORT_VLAN(i),
210 AR8X16_PORT_VLAN_MODE_MASK |
211 AR8X16_VLAN_MEMBER <<
212 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
213 AR8X16_PORT_VLAN_MODE_SECURE <<
214 AR8X16_PORT_VLAN_MODE_SHIFT);
215
216 /*
217 * Setup vlan 1 as PVID for all switch ports. Add all ports
218 * as members of vlan 1.
219 */
220 sc->vid[0] = 1;
221 /* Set PVID for everyone. */
222 for (i = 0; i <= sc->numphys; i++)
175{
176 uint32_t ports;
177 int i, j;
178
179 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
180
181 ARSWITCH_LOCK(sc);
182
183 /* Reset all vlan data. */
184 memset(sc->vid, 0, sizeof(sc->vid));
185
186 /* Disable the QinQ and egress filters for all ports. */
187 for (i = 0; i <= sc->numphys; i++) {
188 if (arswitch_modifyreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(i),
189 0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT |
190 AR8X16_PORT_CTRL_DOUBLE_TAG, 0)) {
191 ARSWITCH_UNLOCK(sc);
192 return;
193 }
194 }
195
196 if (arswitch_flush_dot1q_vlan(sc)) {
197 ARSWITCH_UNLOCK(sc);
198 return;
199 }
200
201 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
202 /*
203 * Reset the port based vlan settings and turn on the
204 * ingress filter for all ports.
205 */
206 ports = 0;
207 for (i = 0; i <= sc->numphys; i++)
208 arswitch_modifyreg(sc->sc_dev,
209 AR8X16_REG_PORT_VLAN(i),
210 AR8X16_PORT_VLAN_MODE_MASK |
211 AR8X16_VLAN_MEMBER <<
212 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
213 AR8X16_PORT_VLAN_MODE_SECURE <<
214 AR8X16_PORT_VLAN_MODE_SHIFT);
215
216 /*
217 * Setup vlan 1 as PVID for all switch ports. Add all ports
218 * as members of vlan 1.
219 */
220 sc->vid[0] = 1;
221 /* Set PVID for everyone. */
222 for (i = 0; i <= sc->numphys; i++)
223 arswitch_set_pvid(sc, i, sc->vid[0]);
223 sc->hal.arswitch_vlan_set_pvid(sc, i, sc->vid[0]);
224 ports = 0;
225 for (i = 0; i <= sc->numphys; i++)
226 ports |= (1 << i);
227 arswitch_set_dot1q_vlan(sc, ports, sc->vid[0]);
228 sc->vid[0] |= ETHERSWITCH_VID_VALID;
229 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
230 /* Initialize the port based vlans. */
231 for (i = 0; i <= sc->numphys; i++) {
232 sc->vid[i] = i | ETHERSWITCH_VID_VALID;
233 ports = 0;
234 for (j = 0; j <= sc->numphys; j++)
235 ports |= (1 << j);
236 arswitch_modifyreg(sc->sc_dev,
237 AR8X16_REG_PORT_VLAN(i),
238 AR8X16_PORT_VLAN_MODE_MASK |
239 AR8X16_VLAN_MEMBER <<
240 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
241 ports << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT |
242 AR8X16_PORT_VLAN_MODE_SECURE <<
243 AR8X16_PORT_VLAN_MODE_PORT_ONLY);
244 }
245 } else {
246 /* Disable the ingress filter and get everyone on all vlans. */
247 for (i = 0; i <= sc->numphys; i++)
248 arswitch_modifyreg(sc->sc_dev,
249 AR8X16_REG_PORT_VLAN(i),
250 AR8X16_PORT_VLAN_MODE_MASK |
251 AR8X16_VLAN_MEMBER <<
252 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
253 AR8X16_VLAN_MEMBER <<
254 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT |
255 AR8X16_PORT_VLAN_MODE_SECURE <<
256 AR8X16_PORT_VLAN_MODE_PORT_ONLY);
257 }
258 ARSWITCH_UNLOCK(sc);
259}
260
261int
224 ports = 0;
225 for (i = 0; i <= sc->numphys; i++)
226 ports |= (1 << i);
227 arswitch_set_dot1q_vlan(sc, ports, sc->vid[0]);
228 sc->vid[0] |= ETHERSWITCH_VID_VALID;
229 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
230 /* Initialize the port based vlans. */
231 for (i = 0; i <= sc->numphys; i++) {
232 sc->vid[i] = i | ETHERSWITCH_VID_VALID;
233 ports = 0;
234 for (j = 0; j <= sc->numphys; j++)
235 ports |= (1 << j);
236 arswitch_modifyreg(sc->sc_dev,
237 AR8X16_REG_PORT_VLAN(i),
238 AR8X16_PORT_VLAN_MODE_MASK |
239 AR8X16_VLAN_MEMBER <<
240 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
241 ports << AR8X16_PORT_VLAN_DEST_PORTS_SHIFT |
242 AR8X16_PORT_VLAN_MODE_SECURE <<
243 AR8X16_PORT_VLAN_MODE_PORT_ONLY);
244 }
245 } else {
246 /* Disable the ingress filter and get everyone on all vlans. */
247 for (i = 0; i <= sc->numphys; i++)
248 arswitch_modifyreg(sc->sc_dev,
249 AR8X16_REG_PORT_VLAN(i),
250 AR8X16_PORT_VLAN_MODE_MASK |
251 AR8X16_VLAN_MEMBER <<
252 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT,
253 AR8X16_VLAN_MEMBER <<
254 AR8X16_PORT_VLAN_DEST_PORTS_SHIFT |
255 AR8X16_PORT_VLAN_MODE_SECURE <<
256 AR8X16_PORT_VLAN_MODE_PORT_ONLY);
257 }
258 ARSWITCH_UNLOCK(sc);
259}
260
261int
262arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
262ar8xxx_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
263{
263{
264 struct arswitch_softc *sc;
265 int err;
266
264 int err;
265
267 sc = device_get_softc(dev);
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 = arswitch_get_dot1q_vlan(sc, &vg->es_member_ports,
292 vg->es_vid);
293 break;
294 case ETHERSWITCH_VLAN_PORT:
295 err = arswitch_get_port_vlan(sc, &vg->es_member_ports,
296 vg->es_vid);
297 break;
298 default:
299 vg->es_member_ports = 0;
300 err = -1;
301 }
302 ARSWITCH_UNLOCK(sc);
303 vg->es_untagged_ports = vg->es_member_ports;
304 return (err);
305}
306
307int
266 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
267
268 if (vg->es_vlangroup > sc->info.es_nvlangroups)
269 return (EINVAL);
270
271 /* Reset the members ports. */
272 vg->es_untagged_ports = 0;
273 vg->es_member_ports = 0;
274
275 /* Not supported. */
276 vg->es_fid = 0;
277
278 /* Vlan ID. */
279 ARSWITCH_LOCK(sc);
280 vg->es_vid = sc->vid[vg->es_vlangroup];
281 if ((vg->es_vid & ETHERSWITCH_VID_VALID) == 0) {
282 ARSWITCH_UNLOCK(sc);
283 return (0);
284 }
285
286 /* Member Ports. */
287 switch (sc->vlan_mode) {
288 case ETHERSWITCH_VLAN_DOT1Q:
289 err = arswitch_get_dot1q_vlan(sc, &vg->es_member_ports,
290 vg->es_vid);
291 break;
292 case ETHERSWITCH_VLAN_PORT:
293 err = arswitch_get_port_vlan(sc, &vg->es_member_ports,
294 vg->es_vid);
295 break;
296 default:
297 vg->es_member_ports = 0;
298 err = -1;
299 }
300 ARSWITCH_UNLOCK(sc);
301 vg->es_untagged_ports = vg->es_member_ports;
302 return (err);
303}
304
305int
308arswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
306ar8xxx_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
309{
307{
310 struct arswitch_softc *sc;
311 int err, vid;
312
308 int err, vid;
309
313 sc = device_get_softc(dev);
314 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
315
316 /* Check VLAN mode. */
317 if (sc->vlan_mode == 0)
318 return (EINVAL);
319
320 /*
321 * Check if we are changing the vlanid for an already used vtu entry.
322 * Then purge the entry first.
323 */
324 ARSWITCH_LOCK(sc);
325 vid = sc->vid[vg->es_vlangroup];
326 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q &&
327 (vid & ETHERSWITCH_VID_VALID) != 0 &&
328 (vid & ETHERSWITCH_VID_MASK) !=
329 (vg->es_vid & ETHERSWITCH_VID_MASK)) {
330 err = arswitch_purge_dot1q_vlan(sc, vid);
331 if (err) {
332 ARSWITCH_UNLOCK(sc);
333 return (err);
334 }
335 }
336
337 /* Vlan ID. */
338 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
339 sc->vid[vg->es_vlangroup] = vg->es_vid & ETHERSWITCH_VID_MASK;
340 /* Setting the vlanid to zero disables the vlangroup. */
341 if (sc->vid[vg->es_vlangroup] == 0) {
342 ARSWITCH_UNLOCK(sc);
343 return (0);
344 }
345 sc->vid[vg->es_vlangroup] |= ETHERSWITCH_VID_VALID;
346 vid = sc->vid[vg->es_vlangroup];
347 }
348
349 /* Member Ports. */
350 switch (sc->vlan_mode) {
351 case ETHERSWITCH_VLAN_DOT1Q:
352 err = arswitch_set_dot1q_vlan(sc, vg->es_member_ports, vid);
353 break;
354 case ETHERSWITCH_VLAN_PORT:
355 err = arswitch_set_port_vlan(sc, vg->es_member_ports, vid);
356 break;
357 default:
358 err = -1;
359 }
360 ARSWITCH_UNLOCK(sc);
361 return (err);
362}
363
364int
310 ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
311
312 /* Check VLAN mode. */
313 if (sc->vlan_mode == 0)
314 return (EINVAL);
315
316 /*
317 * Check if we are changing the vlanid for an already used vtu entry.
318 * Then purge the entry first.
319 */
320 ARSWITCH_LOCK(sc);
321 vid = sc->vid[vg->es_vlangroup];
322 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q &&
323 (vid & ETHERSWITCH_VID_VALID) != 0 &&
324 (vid & ETHERSWITCH_VID_MASK) !=
325 (vg->es_vid & ETHERSWITCH_VID_MASK)) {
326 err = arswitch_purge_dot1q_vlan(sc, vid);
327 if (err) {
328 ARSWITCH_UNLOCK(sc);
329 return (err);
330 }
331 }
332
333 /* Vlan ID. */
334 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
335 sc->vid[vg->es_vlangroup] = vg->es_vid & ETHERSWITCH_VID_MASK;
336 /* Setting the vlanid to zero disables the vlangroup. */
337 if (sc->vid[vg->es_vlangroup] == 0) {
338 ARSWITCH_UNLOCK(sc);
339 return (0);
340 }
341 sc->vid[vg->es_vlangroup] |= ETHERSWITCH_VID_VALID;
342 vid = sc->vid[vg->es_vlangroup];
343 }
344
345 /* Member Ports. */
346 switch (sc->vlan_mode) {
347 case ETHERSWITCH_VLAN_DOT1Q:
348 err = arswitch_set_dot1q_vlan(sc, vg->es_member_ports, vid);
349 break;
350 case ETHERSWITCH_VLAN_PORT:
351 err = arswitch_set_port_vlan(sc, vg->es_member_ports, vid);
352 break;
353 default:
354 err = -1;
355 }
356 ARSWITCH_UNLOCK(sc);
357 return (err);
358}
359
360int
365arswitch_get_pvid(struct arswitch_softc *sc, int port, int *pvid)
361ar8xxx_get_pvid(struct arswitch_softc *sc, int port, int *pvid)
366{
367 uint32_t reg;
368
369 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
370 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port));
371 *pvid = reg & 0xfff;
372 return (0);
373}
374
375int
362{
363 uint32_t reg;
364
365 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
366 reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_VLAN(port));
367 *pvid = reg & 0xfff;
368 return (0);
369}
370
371int
376arswitch_set_pvid(struct arswitch_softc *sc, int port, int pvid)
372ar8xxx_set_pvid(struct arswitch_softc *sc, int port, int pvid)
377{
378
379 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
380 return (arswitch_modifyreg(sc->sc_dev,
381 AR8X16_REG_PORT_VLAN(port), 0xfff, pvid));
382}
373{
374
375 ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
376 return (arswitch_modifyreg(sc->sc_dev,
377 AR8X16_REG_PORT_VLAN(port), 0xfff, pvid));
378}