diff options
author | David S. Miller <davem@davemloft.net> | 2016-08-24 12:41:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-08-24 12:41:13 -0400 |
commit | d14c800ba64d05f1eceb69924ba3f1aeba829abb (patch) | |
tree | 80ac8c3b4009471e3eb66616b96d1505988421de | |
parent | fff84d2a39603336ccb7140e282c4011315e29c4 (diff) | |
parent | 0f7a4d8a9d1c6ecd0a93f7e5feedf5cdffaafd5e (diff) |
Merge branch 'mlxsw-fdb-learning-offload'
Jiri Pirko says:
====================
mlxsw: Offload FDB learning configuration
Ido says:
This patchset addresses two long standing issues in the mlxsw driver
concerning FDB learning.
Patch 1 limits the number of FDB records processed by the driver in a
single session. This is useful in situations in which many new records
need to be processed, thereby causing the RTNL mutex to be held for
long periods of time.
Patches 2-6 offload the learning configuration (on / off) of bridge
ports to the device instead of having the driver decide whether a
record needs to be learned or not.
The last patch is fallout and removes configuration no longer necessary
after the first patches are applied.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/reg.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 24 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 128 |
4 files changed, 115 insertions, 47 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 1721098eef13..b83d0a7a0b49 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h | |||
@@ -591,6 +591,12 @@ static const struct mlxsw_reg_info mlxsw_reg_sfn = { | |||
591 | */ | 591 | */ |
592 | MLXSW_ITEM32(reg, sfn, swid, 0x00, 24, 8); | 592 | MLXSW_ITEM32(reg, sfn, swid, 0x00, 24, 8); |
593 | 593 | ||
594 | /* reg_sfn_end | ||
595 | * Forces the current session to end. | ||
596 | * Access: OP | ||
597 | */ | ||
598 | MLXSW_ITEM32(reg, sfn, end, 0x04, 20, 1); | ||
599 | |||
594 | /* reg_sfn_num_rec | 600 | /* reg_sfn_num_rec |
595 | * Request: Number of learned notifications and aged-out notification | 601 | * Request: Number of learned notifications and aged-out notification |
596 | * records requested. | 602 | * records requested. |
@@ -605,6 +611,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload) | |||
605 | { | 611 | { |
606 | MLXSW_REG_ZERO(sfn, payload); | 612 | MLXSW_REG_ZERO(sfn, payload); |
607 | mlxsw_reg_sfn_swid_set(payload, 0); | 613 | mlxsw_reg_sfn_swid_set(payload, 0); |
614 | mlxsw_reg_sfn_end_set(payload, 1); | ||
608 | mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT); | 615 | mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT); |
609 | } | 616 | } |
610 | 617 | ||
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 1f8168906811..2713a64eae75 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c | |||
@@ -555,8 +555,9 @@ int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, | |||
555 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); | 555 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); |
556 | } | 556 | } |
557 | 557 | ||
558 | static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | 558 | int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, |
559 | u16 vid, bool learn_enable) | 559 | u16 vid_begin, u16 vid_end, |
560 | bool learn_enable) | ||
560 | { | 561 | { |
561 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | 562 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
562 | char *spvmlr_pl; | 563 | char *spvmlr_pl; |
@@ -565,13 +566,20 @@ static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | |||
565 | spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); | 566 | spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); |
566 | if (!spvmlr_pl) | 567 | if (!spvmlr_pl) |
567 | return -ENOMEM; | 568 | return -ENOMEM; |
568 | mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid, | 569 | mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid_begin, |
569 | learn_enable); | 570 | vid_end, learn_enable); |
570 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); | 571 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); |
571 | kfree(spvmlr_pl); | 572 | kfree(spvmlr_pl); |
572 | return err; | 573 | return err; |
573 | } | 574 | } |
574 | 575 | ||
576 | static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
577 | u16 vid, bool learn_enable) | ||
578 | { | ||
579 | return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, | ||
580 | learn_enable); | ||
581 | } | ||
582 | |||
575 | static int | 583 | static int |
576 | mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) | 584 | mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) |
577 | { | 585 | { |
@@ -973,10 +981,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, | |||
973 | goto err_port_vp_mode_trans; | 981 | goto err_port_vp_mode_trans; |
974 | } | 982 | } |
975 | 983 | ||
976 | err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); | ||
977 | if (err) | ||
978 | goto err_port_vid_learning_set; | ||
979 | |||
980 | err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); | 984 | err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); |
981 | if (err) | 985 | if (err) |
982 | goto err_port_add_vid; | 986 | goto err_port_add_vid; |
@@ -984,8 +988,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, | |||
984 | return 0; | 988 | return 0; |
985 | 989 | ||
986 | err_port_add_vid: | 990 | err_port_add_vid: |
987 | mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); | ||
988 | err_port_vid_learning_set: | ||
989 | if (list_is_singular(&mlxsw_sp_port->vports_list)) | 991 | if (list_is_singular(&mlxsw_sp_port->vports_list)) |
990 | mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); | 992 | mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); |
991 | err_port_vp_mode_trans: | 993 | err_port_vp_mode_trans: |
@@ -1012,8 +1014,6 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, | |||
1012 | 1014 | ||
1013 | mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false); | 1015 | mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false); |
1014 | 1016 | ||
1015 | mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); | ||
1016 | |||
1017 | /* Drop FID reference. If this was the last reference the | 1017 | /* Drop FID reference. If this was the last reference the |
1018 | * resources will be freed. | 1018 | * resources will be freed. |
1019 | */ | 1019 | */ |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index ab3feb81bd43..01537d3a1c48 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h | |||
@@ -558,6 +558,9 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu, | |||
558 | int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, | 558 | int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, |
559 | enum mlxsw_reg_qeec_hr hr, u8 index, | 559 | enum mlxsw_reg_qeec_hr hr, u8 index, |
560 | u8 next_index, u32 maxrate); | 560 | u8 next_index, u32 maxrate); |
561 | int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
562 | u16 vid_begin, u16 vid_end, | ||
563 | bool learn_enable); | ||
561 | 564 | ||
562 | #ifdef CONFIG_MLXSW_SPECTRUM_DCB | 565 | #ifdef CONFIG_MLXSW_SPECTRUM_DCB |
563 | 566 | ||
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index d1b59cdfacc1..0c3fbbc6b537 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | |||
@@ -261,12 +261,40 @@ int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, | |||
261 | false); | 261 | false); |
262 | } | 262 | } |
263 | 263 | ||
264 | static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
265 | bool set) | ||
266 | { | ||
267 | u16 vid; | ||
268 | int err; | ||
269 | |||
270 | if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { | ||
271 | vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); | ||
272 | |||
273 | return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, | ||
274 | set); | ||
275 | } | ||
276 | |||
277 | for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { | ||
278 | err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, | ||
279 | set); | ||
280 | if (err) | ||
281 | goto err_port_vid_learning_set; | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | |||
286 | err_port_vid_learning_set: | ||
287 | for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) | ||
288 | __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, !set); | ||
289 | return err; | ||
290 | } | ||
291 | |||
264 | static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, | 292 | static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, |
265 | struct switchdev_trans *trans, | 293 | struct switchdev_trans *trans, |
266 | unsigned long brport_flags) | 294 | unsigned long brport_flags) |
267 | { | 295 | { |
296 | unsigned long learning = mlxsw_sp_port->learning ? BR_LEARNING : 0; | ||
268 | unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0; | 297 | unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0; |
269 | bool set; | ||
270 | int err; | 298 | int err; |
271 | 299 | ||
272 | if (!mlxsw_sp_port->bridged) | 300 | if (!mlxsw_sp_port->bridged) |
@@ -276,17 +304,30 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, | |||
276 | return 0; | 304 | return 0; |
277 | 305 | ||
278 | if ((uc_flood ^ brport_flags) & BR_FLOOD) { | 306 | if ((uc_flood ^ brport_flags) & BR_FLOOD) { |
279 | set = mlxsw_sp_port->uc_flood ? false : true; | 307 | err = mlxsw_sp_port_uc_flood_set(mlxsw_sp_port, |
280 | err = mlxsw_sp_port_uc_flood_set(mlxsw_sp_port, set); | 308 | !mlxsw_sp_port->uc_flood); |
281 | if (err) | 309 | if (err) |
282 | return err; | 310 | return err; |
283 | } | 311 | } |
284 | 312 | ||
313 | if ((learning ^ brport_flags) & BR_LEARNING) { | ||
314 | err = mlxsw_sp_port_learning_set(mlxsw_sp_port, | ||
315 | !mlxsw_sp_port->learning); | ||
316 | if (err) | ||
317 | goto err_port_learning_set; | ||
318 | } | ||
319 | |||
285 | mlxsw_sp_port->uc_flood = brport_flags & BR_FLOOD ? 1 : 0; | 320 | mlxsw_sp_port->uc_flood = brport_flags & BR_FLOOD ? 1 : 0; |
286 | mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0; | 321 | mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0; |
287 | mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0; | 322 | mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0; |
288 | 323 | ||
289 | return 0; | 324 | return 0; |
325 | |||
326 | err_port_learning_set: | ||
327 | if ((uc_flood ^ brport_flags) & BR_FLOOD) | ||
328 | mlxsw_sp_port_uc_flood_set(mlxsw_sp_port, | ||
329 | mlxsw_sp_port->uc_flood); | ||
330 | return err; | ||
290 | } | 331 | } |
291 | 332 | ||
292 | static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) | 333 | static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) |
@@ -635,6 +676,27 @@ static int __mlxsw_sp_port_vlans_set(struct mlxsw_sp_port *mlxsw_sp_port, | |||
635 | return 0; | 676 | return 0; |
636 | } | 677 | } |
637 | 678 | ||
679 | static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, | ||
680 | u16 vid_begin, u16 vid_end, | ||
681 | bool learn_enable) | ||
682 | { | ||
683 | u16 vid, vid_e; | ||
684 | int err; | ||
685 | |||
686 | for (vid = vid_begin; vid <= vid_end; | ||
687 | vid += MLXSW_REG_SPVMLR_REC_MAX_COUNT) { | ||
688 | vid_e = min((u16) (vid + MLXSW_REG_SPVMLR_REC_MAX_COUNT - 1), | ||
689 | vid_end); | ||
690 | |||
691 | err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, | ||
692 | vid_e, learn_enable); | ||
693 | if (err) | ||
694 | return err; | ||
695 | } | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
638 | static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, | 700 | static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, |
639 | u16 vid_begin, u16 vid_end, | 701 | u16 vid_begin, u16 vid_end, |
640 | bool flag_untagged, bool flag_pvid) | 702 | bool flag_untagged, bool flag_pvid) |
@@ -675,6 +737,14 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, | |||
675 | } | 737 | } |
676 | } | 738 | } |
677 | 739 | ||
740 | err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, | ||
741 | mlxsw_sp_port->learning); | ||
742 | if (err) { | ||
743 | netdev_err(dev, "Failed to set learning for VIDs %d-%d\n", | ||
744 | vid_begin, vid_end); | ||
745 | goto err_port_vid_learning_set; | ||
746 | } | ||
747 | |||
678 | /* Changing activity bits only if HW operation succeded */ | 748 | /* Changing activity bits only if HW operation succeded */ |
679 | for (vid = vid_begin; vid <= vid_end; vid++) { | 749 | for (vid = vid_begin; vid <= vid_end; vid++) { |
680 | set_bit(vid, mlxsw_sp_port->active_vlans); | 750 | set_bit(vid, mlxsw_sp_port->active_vlans); |
@@ -697,6 +767,9 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, | |||
697 | err_port_stp_state_set: | 767 | err_port_stp_state_set: |
698 | for (vid = vid_begin; vid <= vid_end; vid++) | 768 | for (vid = vid_begin; vid <= vid_end; vid++) |
699 | clear_bit(vid, mlxsw_sp_port->active_vlans); | 769 | clear_bit(vid, mlxsw_sp_port->active_vlans); |
770 | mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, | ||
771 | false); | ||
772 | err_port_vid_learning_set: | ||
700 | if (old_pvid != mlxsw_sp_port->pvid) | 773 | if (old_pvid != mlxsw_sp_port->pvid) |
701 | mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); | 774 | mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); |
702 | err_port_pvid_set: | 775 | err_port_pvid_set: |
@@ -1001,29 +1074,20 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, | |||
1001 | static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, | 1074 | static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, |
1002 | u16 vid_begin, u16 vid_end) | 1075 | u16 vid_begin, u16 vid_end) |
1003 | { | 1076 | { |
1004 | struct net_device *dev = mlxsw_sp_port->dev; | ||
1005 | u16 vid, pvid; | 1077 | u16 vid, pvid; |
1006 | int err; | ||
1007 | 1078 | ||
1008 | if (!mlxsw_sp_port->bridged) | 1079 | if (!mlxsw_sp_port->bridged) |
1009 | return -EINVAL; | 1080 | return -EINVAL; |
1010 | 1081 | ||
1011 | err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end, | 1082 | mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, |
1012 | false, false); | 1083 | false); |
1013 | if (err) { | ||
1014 | netdev_err(dev, "Unable to del VIDs %d-%d\n", vid_begin, | ||
1015 | vid_end); | ||
1016 | return err; | ||
1017 | } | ||
1018 | 1084 | ||
1019 | pvid = mlxsw_sp_port->pvid; | 1085 | pvid = mlxsw_sp_port->pvid; |
1020 | if (pvid >= vid_begin && pvid <= vid_end) { | 1086 | if (pvid >= vid_begin && pvid <= vid_end) |
1021 | err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); | 1087 | mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); |
1022 | if (err) { | 1088 | |
1023 | netdev_err(dev, "Unable to del PVID %d\n", pvid); | 1089 | __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end, false, |
1024 | return err; | 1090 | false); |
1025 | } | ||
1026 | } | ||
1027 | 1091 | ||
1028 | mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); | 1092 | mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); |
1029 | 1093 | ||
@@ -1366,8 +1430,6 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, | |||
1366 | vid = fid; | 1430 | vid = fid; |
1367 | } | 1431 | } |
1368 | 1432 | ||
1369 | adding = adding && mlxsw_sp_port->learning; | ||
1370 | |||
1371 | do_fdb_op: | 1433 | do_fdb_op: |
1372 | err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, | 1434 | err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, |
1373 | adding, true); | 1435 | adding, true); |
@@ -1429,8 +1491,6 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, | |||
1429 | vid = fid; | 1491 | vid = fid; |
1430 | } | 1492 | } |
1431 | 1493 | ||
1432 | adding = adding && mlxsw_sp_port->learning; | ||
1433 | |||
1434 | do_fdb_op: | 1494 | do_fdb_op: |
1435 | err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid, | 1495 | err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid, |
1436 | adding, true); | 1496 | adding, true); |
@@ -1496,20 +1556,18 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) | |||
1496 | mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); | 1556 | mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); |
1497 | 1557 | ||
1498 | rtnl_lock(); | 1558 | rtnl_lock(); |
1499 | do { | 1559 | mlxsw_reg_sfn_pack(sfn_pl); |
1500 | mlxsw_reg_sfn_pack(sfn_pl); | 1560 | err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); |
1501 | err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); | 1561 | if (err) { |
1502 | if (err) { | 1562 | dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n"); |
1503 | dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n"); | 1563 | goto out; |
1504 | break; | 1564 | } |
1505 | } | 1565 | num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl); |
1506 | num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl); | 1566 | for (i = 0; i < num_rec; i++) |
1507 | for (i = 0; i < num_rec; i++) | 1567 | mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); |
1508 | mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); | ||
1509 | 1568 | ||
1510 | } while (num_rec); | 1569 | out: |
1511 | rtnl_unlock(); | 1570 | rtnl_unlock(); |
1512 | |||
1513 | kfree(sfn_pl); | 1571 | kfree(sfn_pl); |
1514 | mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); | 1572 | mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); |
1515 | } | 1573 | } |