aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-08-24 12:41:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-24 12:41:13 -0400
commitd14c800ba64d05f1eceb69924ba3f1aeba829abb (patch)
tree80ac8c3b4009471e3eb66616b96d1505988421de
parentfff84d2a39603336ccb7140e282c4011315e29c4 (diff)
parent0f7a4d8a9d1c6ecd0a93f7e5feedf5cdffaafd5e (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.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c128
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 */
592MLXSW_ITEM32(reg, sfn, swid, 0x00, 24, 8); 592MLXSW_ITEM32(reg, sfn, swid, 0x00, 24, 8);
593 593
594/* reg_sfn_end
595 * Forces the current session to end.
596 * Access: OP
597 */
598MLXSW_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
558static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, 558int __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
576static 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
575static int 583static int
576mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) 584mlxsw_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
986err_port_add_vid: 990err_port_add_vid:
987 mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true);
988err_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);
991err_port_vp_mode_trans: 993err_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,
558int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, 558int 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);
561int __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
264static 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
286err_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
264static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, 292static 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
326err_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
292static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) 333static 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
679static 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
638static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, 700static 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,
697err_port_stp_state_set: 767err_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);
772err_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);
702err_port_pvid_set: 775err_port_pvid_set:
@@ -1001,29 +1074,20 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev,
1001static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, 1074static 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
1371do_fdb_op: 1433do_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
1434do_fdb_op: 1494do_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); 1569out:
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}