port.c (36cbf39b56908bb2e7e8e392e5f08895c3ca4326) port.c (d3eed0e57d5d1bcbf1bd60f83a4adfe7d7b8dd9c)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Handling of a single switch port
4 *
5 * Copyright (c) 2017 Savoir-faire Linux Inc.
6 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 */
8

--- 116 unchanged lines hidden (view full) ---

125 int err;
126
127 if (ds->ops->port_enable) {
128 err = ds->ops->port_enable(ds, port, phy);
129 if (err)
130 return err;
131 }
132
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Handling of a single switch port
4 *
5 * Copyright (c) 2017 Savoir-faire Linux Inc.
6 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 */
8

--- 116 unchanged lines hidden (view full) ---

125 int err;
126
127 if (ds->ops->port_enable) {
128 err = ds->ops->port_enable(ds, port, phy);
129 if (err)
130 return err;
131 }
132
133 if (!dp->bridge_dev)
133 if (!dp->bridge)
134 dsa_port_set_state_now(dp, BR_STATE_FORWARDING, false);
135
136 if (dp->pl)
137 phylink_start(dp->pl);
138
139 return 0;
140}
141

--- 11 unchanged lines hidden (view full) ---

153void dsa_port_disable_rt(struct dsa_port *dp)
154{
155 struct dsa_switch *ds = dp->ds;
156 int port = dp->index;
157
158 if (dp->pl)
159 phylink_stop(dp->pl);
160
134 dsa_port_set_state_now(dp, BR_STATE_FORWARDING, false);
135
136 if (dp->pl)
137 phylink_start(dp->pl);
138
139 return 0;
140}
141

--- 11 unchanged lines hidden (view full) ---

153void dsa_port_disable_rt(struct dsa_port *dp)
154{
155 struct dsa_switch *ds = dp->ds;
156 int port = dp->index;
157
158 if (dp->pl)
159 phylink_stop(dp->pl);
160
161 if (!dp->bridge_dev)
161 if (!dp->bridge)
162 dsa_port_set_state_now(dp, BR_STATE_DISABLED, false);
163
164 if (ds->ops->port_disable)
165 ds->ops->port_disable(ds, port);
166}
167
168void dsa_port_disable(struct dsa_port *dp)
169{

--- 96 unchanged lines hidden (view full) ---

266 /* VLAN filtering is handled by dsa_switch_bridge_leave */
267
268 /* Ageing time may be global to the switch chip, so don't change it
269 * here because we have no good reason (or value) to change it to.
270 */
271}
272
273static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
162 dsa_port_set_state_now(dp, BR_STATE_DISABLED, false);
163
164 if (ds->ops->port_disable)
165 ds->ops->port_disable(ds, port);
166}
167
168void dsa_port_disable(struct dsa_port *dp)
169{

--- 96 unchanged lines hidden (view full) ---

266 /* VLAN filtering is handled by dsa_switch_bridge_leave */
267
268 /* Ageing time may be global to the switch chip, so don't change it
269 * here because we have no good reason (or value) to change it to.
270 */
271}
272
273static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
274 struct net_device *bridge_dev,
275 unsigned int bridge_num)
274 struct dsa_bridge bridge)
276{
277 struct dsa_switch *ds = dp->ds;
278
279 /* No bridge TX forwarding offload => do nothing */
275{
276 struct dsa_switch *ds = dp->ds;
277
278 /* No bridge TX forwarding offload => do nothing */
280 if (!ds->ops->port_bridge_tx_fwd_unoffload || !bridge_num)
279 if (!ds->ops->port_bridge_tx_fwd_unoffload || !bridge.num)
281 return;
282
283 /* Notify the chips only once the offload has been deactivated, so
284 * that they can update their configuration accordingly.
285 */
280 return;
281
282 /* Notify the chips only once the offload has been deactivated, so
283 * that they can update their configuration accordingly.
284 */
286 ds->ops->port_bridge_tx_fwd_unoffload(ds, dp->index, bridge_dev,
287 bridge_num);
285 ds->ops->port_bridge_tx_fwd_unoffload(ds, dp->index, bridge);
288}
289
290static bool dsa_port_bridge_tx_fwd_offload(struct dsa_port *dp,
286}
287
288static bool dsa_port_bridge_tx_fwd_offload(struct dsa_port *dp,
291 struct net_device *bridge_dev,
292 unsigned int bridge_num)
289 struct dsa_bridge bridge)
293{
294 struct dsa_switch *ds = dp->ds;
295 int err;
296
297 /* FDB isolation is required for TX forwarding offload */
290{
291 struct dsa_switch *ds = dp->ds;
292 int err;
293
294 /* FDB isolation is required for TX forwarding offload */
298 if (!ds->ops->port_bridge_tx_fwd_offload || !bridge_num)
295 if (!ds->ops->port_bridge_tx_fwd_offload || !bridge.num)
299 return false;
300
301 /* Notify the driver */
296 return false;
297
298 /* Notify the driver */
302 err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge_dev,
303 bridge_num);
299 err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge);
304
305 return err ? false : true;
306}
307
308static int dsa_port_bridge_create(struct dsa_port *dp,
309 struct net_device *br,
310 struct netlink_ext_ack *extack)
311{
312 struct dsa_switch *ds = dp->ds;
300
301 return err ? false : true;
302}
303
304static int dsa_port_bridge_create(struct dsa_port *dp,
305 struct net_device *br,
306 struct netlink_ext_ack *extack)
307{
308 struct dsa_switch *ds = dp->ds;
313 unsigned int bridge_num;
309 struct dsa_bridge *bridge;
314
310
315 dp->bridge_dev = br;
316
317 if (!ds->max_num_bridges)
311 bridge = dsa_tree_bridge_find(ds->dst, br);
312 if (bridge) {
313 refcount_inc(&bridge->refcount);
314 dp->bridge = bridge;
318 return 0;
315 return 0;
316 }
319
317
320 bridge_num = dsa_bridge_num_get(br, ds->max_num_bridges);
321 if (!bridge_num) {
318 bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
319 if (!bridge)
320 return -ENOMEM;
321
322 refcount_set(&bridge->refcount, 1);
323
324 bridge->dev = br;
325
326 bridge->num = dsa_bridge_num_get(br, ds->max_num_bridges);
327 if (ds->max_num_bridges && !bridge->num) {
322 NL_SET_ERR_MSG_MOD(extack,
323 "Range of offloadable bridges exceeded");
328 NL_SET_ERR_MSG_MOD(extack,
329 "Range of offloadable bridges exceeded");
330 kfree(bridge);
324 return -EOPNOTSUPP;
325 }
326
331 return -EOPNOTSUPP;
332 }
333
327 dp->bridge_num = bridge_num;
334 dp->bridge = bridge;
328
329 return 0;
330}
331
332static void dsa_port_bridge_destroy(struct dsa_port *dp,
333 const struct net_device *br)
334{
335
336 return 0;
337}
338
339static void dsa_port_bridge_destroy(struct dsa_port *dp,
340 const struct net_device *br)
341{
335 struct dsa_switch *ds = dp->ds;
342 struct dsa_bridge *bridge = dp->bridge;
336
343
337 dp->bridge_dev = NULL;
344 dp->bridge = NULL;
338
345
339 if (ds->max_num_bridges) {
340 int bridge_num = dp->bridge_num;
346 if (!refcount_dec_and_test(&bridge->refcount))
347 return;
341
348
342 dp->bridge_num = 0;
343 dsa_bridge_num_put(br, bridge_num);
344 }
349 if (bridge->num)
350 dsa_bridge_num_put(br, bridge->num);
351
352 kfree(bridge);
345}
346
347int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
348 struct netlink_ext_ack *extack)
349{
350 struct dsa_notifier_bridge_info info = {
351 .tree_index = dp->ds->dst->index,
352 .sw_index = dp->ds->index,
353 .port = dp->index,
353}
354
355int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
356 struct netlink_ext_ack *extack)
357{
358 struct dsa_notifier_bridge_info info = {
359 .tree_index = dp->ds->dst->index,
360 .sw_index = dp->ds->index,
361 .port = dp->index,
354 .br = br,
355 };
356 struct net_device *dev = dp->slave;
357 struct net_device *brport_dev;
358 bool tx_fwd_offload;
359 int err;
360
361 /* Here the interface is already bridged. Reflect the current
362 * configuration so that drivers can program their chips accordingly.
363 */
364 err = dsa_port_bridge_create(dp, br, extack);
365 if (err)
366 return err;
367
368 brport_dev = dsa_port_to_bridge_port(dp);
369
362 };
363 struct net_device *dev = dp->slave;
364 struct net_device *brport_dev;
365 bool tx_fwd_offload;
366 int err;
367
368 /* Here the interface is already bridged. Reflect the current
369 * configuration so that drivers can program their chips accordingly.
370 */
371 err = dsa_port_bridge_create(dp, br, extack);
372 if (err)
373 return err;
374
375 brport_dev = dsa_port_to_bridge_port(dp);
376
377 info.bridge = *dp->bridge;
370 err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info);
371 if (err)
372 goto out_rollback;
373
378 err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info);
379 if (err)
380 goto out_rollback;
381
374 tx_fwd_offload = dsa_port_bridge_tx_fwd_offload(dp, br,
375 dsa_port_bridge_num_get(dp));
382 tx_fwd_offload = dsa_port_bridge_tx_fwd_offload(dp, info.bridge);
376
377 err = switchdev_bridge_port_offload(brport_dev, dev, dp,
378 &dsa_slave_switchdev_notifier,
379 &dsa_slave_switchdev_blocking_notifier,
380 tx_fwd_offload, extack);
381 if (err)
382 goto out_rollback_unbridge;
383

--- 26 unchanged lines hidden (view full) ---

410 &dsa_slave_switchdev_notifier,
411 &dsa_slave_switchdev_blocking_notifier);
412
413 dsa_flush_workqueue();
414}
415
416void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
417{
383
384 err = switchdev_bridge_port_offload(brport_dev, dev, dp,
385 &dsa_slave_switchdev_notifier,
386 &dsa_slave_switchdev_blocking_notifier,
387 tx_fwd_offload, extack);
388 if (err)
389 goto out_rollback_unbridge;
390

--- 26 unchanged lines hidden (view full) ---

417 &dsa_slave_switchdev_notifier,
418 &dsa_slave_switchdev_blocking_notifier);
419
420 dsa_flush_workqueue();
421}
422
423void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
424{
418 unsigned int bridge_num = dsa_port_bridge_num_get(dp);
419 struct dsa_notifier_bridge_info info = {
420 .tree_index = dp->ds->dst->index,
421 .sw_index = dp->ds->index,
422 .port = dp->index,
425 struct dsa_notifier_bridge_info info = {
426 .tree_index = dp->ds->dst->index,
427 .sw_index = dp->ds->index,
428 .port = dp->index,
423 .br = br,
429 .bridge = *dp->bridge,
424 };
425 int err;
426
427 /* Here the port is already unbridged. Reflect the current configuration
428 * so that drivers can program their chips accordingly.
429 */
430 dsa_port_bridge_destroy(dp, br);
431
430 };
431 int err;
432
433 /* Here the port is already unbridged. Reflect the current configuration
434 * so that drivers can program their chips accordingly.
435 */
436 dsa_port_bridge_destroy(dp, br);
437
432 dsa_port_bridge_tx_fwd_unoffload(dp, br, bridge_num);
438 dsa_port_bridge_tx_fwd_unoffload(dp, info.bridge);
433
434 err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
435 if (err)
436 dev_err(dp->ds->dev,
437 "port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
438 dp->index, ERR_PTR(err));
439
440 dsa_port_switchdev_unsync_attrs(dp);

--- 971 unchanged lines hidden ---
439
440 err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
441 if (err)
442 dev_err(dp->ds->dev,
443 "port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
444 dp->index, ERR_PTR(err));
445
446 dsa_port_switchdev_unsync_attrs(dp);

--- 971 unchanged lines hidden ---