diff options
Diffstat (limited to 'net/dsa/switch.c')
-rw-r--r-- | net/dsa/switch.c | 132 |
1 files changed, 59 insertions, 73 deletions
diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 09d9286b27cc..489eb7b430a4 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c | |||
@@ -128,57 +128,51 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds, | |||
128 | return ds->ops->port_fdb_del(ds, port, info->addr, info->vid); | 128 | return ds->ops->port_fdb_del(ds, port, info->addr, info->vid); |
129 | } | 129 | } |
130 | 130 | ||
131 | static int | 131 | static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port, |
132 | dsa_switch_mdb_prepare_bitmap(struct dsa_switch *ds, | 132 | struct dsa_notifier_mdb_info *info) |
133 | const struct switchdev_obj_port_mdb *mdb, | 133 | { |
134 | const unsigned long *bitmap) | 134 | if (ds->index == info->sw_index && port == info->port) |
135 | return true; | ||
136 | |||
137 | if (dsa_is_dsa_port(ds, port)) | ||
138 | return true; | ||
139 | |||
140 | return false; | ||
141 | } | ||
142 | |||
143 | static int dsa_switch_mdb_prepare(struct dsa_switch *ds, | ||
144 | struct dsa_notifier_mdb_info *info) | ||
135 | { | 145 | { |
136 | int port, err; | 146 | int port, err; |
137 | 147 | ||
138 | if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) | 148 | if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) |
139 | return -EOPNOTSUPP; | 149 | return -EOPNOTSUPP; |
140 | 150 | ||
141 | for_each_set_bit(port, bitmap, ds->num_ports) { | 151 | for (port = 0; port < ds->num_ports; port++) { |
142 | err = ds->ops->port_mdb_prepare(ds, port, mdb); | 152 | if (dsa_switch_mdb_match(ds, port, info)) { |
143 | if (err) | 153 | err = ds->ops->port_mdb_prepare(ds, port, info->mdb); |
144 | return err; | 154 | if (err) |
155 | return err; | ||
156 | } | ||
145 | } | 157 | } |
146 | 158 | ||
147 | return 0; | 159 | return 0; |
148 | } | 160 | } |
149 | 161 | ||
150 | static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds, | ||
151 | const struct switchdev_obj_port_mdb *mdb, | ||
152 | const unsigned long *bitmap) | ||
153 | { | ||
154 | int port; | ||
155 | |||
156 | if (!ds->ops->port_mdb_add) | ||
157 | return; | ||
158 | |||
159 | for_each_set_bit(port, bitmap, ds->num_ports) | ||
160 | ds->ops->port_mdb_add(ds, port, mdb); | ||
161 | } | ||
162 | |||
163 | static int dsa_switch_mdb_add(struct dsa_switch *ds, | 162 | static int dsa_switch_mdb_add(struct dsa_switch *ds, |
164 | struct dsa_notifier_mdb_info *info) | 163 | struct dsa_notifier_mdb_info *info) |
165 | { | 164 | { |
166 | const struct switchdev_obj_port_mdb *mdb = info->mdb; | ||
167 | struct switchdev_trans *trans = info->trans; | ||
168 | int port; | 165 | int port; |
169 | 166 | ||
170 | /* Build a mask of Multicast group members */ | 167 | if (switchdev_trans_ph_prepare(info->trans)) |
171 | bitmap_zero(ds->bitmap, ds->num_ports); | 168 | return dsa_switch_mdb_prepare(ds, info); |
172 | if (ds->index == info->sw_index) | ||
173 | set_bit(info->port, ds->bitmap); | ||
174 | for (port = 0; port < ds->num_ports; port++) | ||
175 | if (dsa_is_dsa_port(ds, port)) | ||
176 | set_bit(port, ds->bitmap); | ||
177 | 169 | ||
178 | if (switchdev_trans_ph_prepare(trans)) | 170 | if (!ds->ops->port_mdb_add) |
179 | return dsa_switch_mdb_prepare_bitmap(ds, mdb, ds->bitmap); | 171 | return 0; |
180 | 172 | ||
181 | dsa_switch_mdb_add_bitmap(ds, mdb, ds->bitmap); | 173 | for (port = 0; port < ds->num_ports; port++) |
174 | if (dsa_switch_mdb_match(ds, port, info)) | ||
175 | ds->ops->port_mdb_add(ds, port, info->mdb); | ||
182 | 176 | ||
183 | return 0; | 177 | return 0; |
184 | } | 178 | } |
@@ -186,13 +180,11 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds, | |||
186 | static int dsa_switch_mdb_del(struct dsa_switch *ds, | 180 | static int dsa_switch_mdb_del(struct dsa_switch *ds, |
187 | struct dsa_notifier_mdb_info *info) | 181 | struct dsa_notifier_mdb_info *info) |
188 | { | 182 | { |
189 | const struct switchdev_obj_port_mdb *mdb = info->mdb; | ||
190 | |||
191 | if (!ds->ops->port_mdb_del) | 183 | if (!ds->ops->port_mdb_del) |
192 | return -EOPNOTSUPP; | 184 | return -EOPNOTSUPP; |
193 | 185 | ||
194 | if (ds->index == info->sw_index) | 186 | if (ds->index == info->sw_index) |
195 | return ds->ops->port_mdb_del(ds, info->port, mdb); | 187 | return ds->ops->port_mdb_del(ds, info->port, info->mdb); |
196 | 188 | ||
197 | return 0; | 189 | return 0; |
198 | } | 190 | } |
@@ -234,59 +226,55 @@ static int dsa_port_vlan_check(struct dsa_switch *ds, int port, | |||
234 | (void *)vlan); | 226 | (void *)vlan); |
235 | } | 227 | } |
236 | 228 | ||
237 | static int | 229 | static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, |
238 | dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds, | 230 | struct dsa_notifier_vlan_info *info) |
239 | const struct switchdev_obj_port_vlan *vlan, | 231 | { |
240 | const unsigned long *bitmap) | 232 | if (ds->index == info->sw_index && port == info->port) |
233 | return true; | ||
234 | |||
235 | if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) | ||
236 | return true; | ||
237 | |||
238 | return false; | ||
239 | } | ||
240 | |||
241 | static int dsa_switch_vlan_prepare(struct dsa_switch *ds, | ||
242 | struct dsa_notifier_vlan_info *info) | ||
241 | { | 243 | { |
242 | int port, err; | 244 | int port, err; |
243 | 245 | ||
244 | if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) | 246 | if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) |
245 | return -EOPNOTSUPP; | 247 | return -EOPNOTSUPP; |
246 | 248 | ||
247 | for_each_set_bit(port, bitmap, ds->num_ports) { | 249 | for (port = 0; port < ds->num_ports; port++) { |
248 | err = dsa_port_vlan_check(ds, port, vlan); | 250 | if (dsa_switch_vlan_match(ds, port, info)) { |
249 | if (err) | 251 | err = dsa_port_vlan_check(ds, port, info->vlan); |
250 | return err; | 252 | if (err) |
253 | return err; | ||
251 | 254 | ||
252 | err = ds->ops->port_vlan_prepare(ds, port, vlan); | 255 | err = ds->ops->port_vlan_prepare(ds, port, info->vlan); |
253 | if (err) | 256 | if (err) |
254 | return err; | 257 | return err; |
258 | } | ||
255 | } | 259 | } |
256 | 260 | ||
257 | return 0; | 261 | return 0; |
258 | } | 262 | } |
259 | 263 | ||
260 | static void | ||
261 | dsa_switch_vlan_add_bitmap(struct dsa_switch *ds, | ||
262 | const struct switchdev_obj_port_vlan *vlan, | ||
263 | const unsigned long *bitmap) | ||
264 | { | ||
265 | int port; | ||
266 | |||
267 | for_each_set_bit(port, bitmap, ds->num_ports) | ||
268 | ds->ops->port_vlan_add(ds, port, vlan); | ||
269 | } | ||
270 | |||
271 | static int dsa_switch_vlan_add(struct dsa_switch *ds, | 264 | static int dsa_switch_vlan_add(struct dsa_switch *ds, |
272 | struct dsa_notifier_vlan_info *info) | 265 | struct dsa_notifier_vlan_info *info) |
273 | { | 266 | { |
274 | const struct switchdev_obj_port_vlan *vlan = info->vlan; | ||
275 | struct switchdev_trans *trans = info->trans; | ||
276 | int port; | 267 | int port; |
277 | 268 | ||
278 | /* Build a mask of VLAN members */ | 269 | if (switchdev_trans_ph_prepare(info->trans)) |
279 | bitmap_zero(ds->bitmap, ds->num_ports); | 270 | return dsa_switch_vlan_prepare(ds, info); |
280 | if (ds->index == info->sw_index) | ||
281 | set_bit(info->port, ds->bitmap); | ||
282 | for (port = 0; port < ds->num_ports; port++) | ||
283 | if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) | ||
284 | set_bit(port, ds->bitmap); | ||
285 | 271 | ||
286 | if (switchdev_trans_ph_prepare(trans)) | 272 | if (!ds->ops->port_vlan_add) |
287 | return dsa_switch_vlan_prepare_bitmap(ds, vlan, ds->bitmap); | 273 | return 0; |
288 | 274 | ||
289 | dsa_switch_vlan_add_bitmap(ds, vlan, ds->bitmap); | 275 | for (port = 0; port < ds->num_ports; port++) |
276 | if (dsa_switch_vlan_match(ds, port, info)) | ||
277 | ds->ops->port_vlan_add(ds, port, info->vlan); | ||
290 | 278 | ||
291 | return 0; | 279 | return 0; |
292 | } | 280 | } |
@@ -294,13 +282,11 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds, | |||
294 | static int dsa_switch_vlan_del(struct dsa_switch *ds, | 282 | static int dsa_switch_vlan_del(struct dsa_switch *ds, |
295 | struct dsa_notifier_vlan_info *info) | 283 | struct dsa_notifier_vlan_info *info) |
296 | { | 284 | { |
297 | const struct switchdev_obj_port_vlan *vlan = info->vlan; | ||
298 | |||
299 | if (!ds->ops->port_vlan_del) | 285 | if (!ds->ops->port_vlan_del) |
300 | return -EOPNOTSUPP; | 286 | return -EOPNOTSUPP; |
301 | 287 | ||
302 | if (ds->index == info->sw_index) | 288 | if (ds->index == info->sw_index) |
303 | return ds->ops->port_vlan_del(ds, info->port, vlan); | 289 | return ds->ops->port_vlan_del(ds, info->port, info->vlan); |
304 | 290 | ||
305 | return 0; | 291 | return 0; |
306 | } | 292 | } |