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 --- |