Commit efa8c819 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-fixes'

Ido Schimmel says:

====================
mlxsw: Various fixes

This patchset contains small fixes in mlxsw and one fix in the bridge
driver.

Patches #1-#4 perform small adjustments in PCI and FID code following
recent tests that were performed on the Spectrum-2 ASIC.

Patch #5 fixes the bridge driver to mark FDB entries that were added by
user as such. Otherwise, these entries will be ignored by underlying
switch drivers.

Patch #6 fixes a long standing issue in mlxsw where the driver
incorrectly programmed static FDB entries as both static and sticky.

Patches #7-#8 add test cases for above mentioned bugs.

Please consider patches #1, #2 and #4 for stable.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 20f5248a 479a2b76
...@@ -604,29 +604,31 @@ static void mlxsw_pci_cq_tasklet(unsigned long data) ...@@ -604,29 +604,31 @@ static void mlxsw_pci_cq_tasklet(unsigned long data)
u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe); u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe);
u8 sendq = mlxsw_pci_cqe_sr_get(q->u.cq.v, cqe); u8 sendq = mlxsw_pci_cqe_sr_get(q->u.cq.v, cqe);
u8 dqn = mlxsw_pci_cqe_dqn_get(q->u.cq.v, cqe); u8 dqn = mlxsw_pci_cqe_dqn_get(q->u.cq.v, cqe);
char ncqe[MLXSW_PCI_CQE_SIZE_MAX];
memcpy(ncqe, cqe, q->elem_size);
mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
if (sendq) { if (sendq) {
struct mlxsw_pci_queue *sdq; struct mlxsw_pci_queue *sdq;
sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn); sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn);
mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq, mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq,
wqe_counter, cqe); wqe_counter, ncqe);
q->u.cq.comp_sdq_count++; q->u.cq.comp_sdq_count++;
} else { } else {
struct mlxsw_pci_queue *rdq; struct mlxsw_pci_queue *rdq;
rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn); rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn);
mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq, mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq,
wqe_counter, q->u.cq.v, cqe); wqe_counter, q->u.cq.v, ncqe);
q->u.cq.comp_rdq_count++; q->u.cq.comp_rdq_count++;
} }
if (++items == credits) if (++items == credits)
break; break;
} }
if (items) { if (items)
mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q);
mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q);
}
} }
static u16 mlxsw_pci_cq_elem_count(const struct mlxsw_pci_queue *q) static u16 mlxsw_pci_cq_elem_count(const struct mlxsw_pci_queue *q)
...@@ -1365,10 +1367,10 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, ...@@ -1365,10 +1367,10 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY); u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC) if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC)
break; return 0;
cond_resched(); cond_resched();
} while (time_before(jiffies, end)); } while (time_before(jiffies, end));
return 0; return -EBUSY;
} }
static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci) static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci)
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define MLXSW_PCI_SW_RESET 0xF0010 #define MLXSW_PCI_SW_RESET 0xF0010
#define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) #define MLXSW_PCI_SW_RESET_RST_BIT BIT(0)
#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 5000 #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 13000
#define MLXSW_PCI_SW_RESET_WAIT_MSECS 100 #define MLXSW_PCI_SW_RESET_WAIT_MSECS 100
#define MLXSW_PCI_FW_READY 0xA1844 #define MLXSW_PCI_FW_READY 0xA1844
#define MLXSW_PCI_FW_READY_MASK 0xFFFF #define MLXSW_PCI_FW_READY_MASK 0xFFFF
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */ #define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */
#define MLXSW_PCI_CQE01_SIZE 16 /* 16 bytes per element */ #define MLXSW_PCI_CQE01_SIZE 16 /* 16 bytes per element */
#define MLXSW_PCI_CQE2_SIZE 32 /* 32 bytes per element */ #define MLXSW_PCI_CQE2_SIZE 32 /* 32 bytes per element */
#define MLXSW_PCI_CQE_SIZE_MAX MLXSW_PCI_CQE2_SIZE
#define MLXSW_PCI_EQE_SIZE 16 /* 16 bytes per element */ #define MLXSW_PCI_EQE_SIZE 16 /* 16 bytes per element */
#define MLXSW_PCI_WQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_WQE_SIZE) #define MLXSW_PCI_WQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_WQE_SIZE)
#define MLXSW_PCI_CQE01_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_CQE01_SIZE) #define MLXSW_PCI_CQE01_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_CQE01_SIZE)
......
...@@ -997,8 +997,8 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { ...@@ -997,8 +997,8 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
.type = MLXSW_SP_FID_TYPE_DUMMY, .type = MLXSW_SP_FID_TYPE_DUMMY,
.fid_size = sizeof(struct mlxsw_sp_fid), .fid_size = sizeof(struct mlxsw_sp_fid),
.start_index = MLXSW_SP_RFID_BASE - 1, .start_index = VLAN_N_VID - 1,
.end_index = MLXSW_SP_RFID_BASE - 1, .end_index = VLAN_N_VID - 1,
.ops = &mlxsw_sp_fid_dummy_ops, .ops = &mlxsw_sp_fid_dummy_ops,
}; };
......
...@@ -1233,7 +1233,7 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, ...@@ -1233,7 +1233,7 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic) static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
{ {
return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS : return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY; MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_MLAG;
} }
static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding) static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
...@@ -1290,7 +1290,7 @@ static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp, ...@@ -1290,7 +1290,7 @@ static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp,
static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const char *mac, u16 fid, bool adding, const char *mac, u16 fid, bool adding,
enum mlxsw_reg_sfd_rec_action action, enum mlxsw_reg_sfd_rec_action action,
bool dynamic) enum mlxsw_reg_sfd_rec_policy policy)
{ {
char *sfd_pl; char *sfd_pl;
u8 num_rec; u8 num_rec;
...@@ -1301,8 +1301,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, ...@@ -1301,8 +1301,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
return -ENOMEM; return -ENOMEM;
mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy, mac, fid, action, local_port);
mac, fid, action, local_port);
num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
if (err) if (err)
...@@ -1321,7 +1320,8 @@ static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, ...@@ -1321,7 +1320,8 @@ static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
bool dynamic) bool dynamic)
{ {
return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding, return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
MLXSW_REG_SFD_REC_ACTION_NOP, dynamic); MLXSW_REG_SFD_REC_ACTION_NOP,
mlxsw_sp_sfd_rec_policy(dynamic));
} }
int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
...@@ -1329,7 +1329,7 @@ int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, ...@@ -1329,7 +1329,7 @@ int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
{ {
return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding, return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER, MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
false); MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY);
} }
static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
......
...@@ -1128,6 +1128,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, ...@@ -1128,6 +1128,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
err = -ENOMEM; err = -ENOMEM;
goto err_unlock; goto err_unlock;
} }
if (swdev_notify)
fdb->added_by_user = 1;
fdb->added_by_external_learn = 1; fdb->added_by_external_learn = 1;
fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
} else { } else {
...@@ -1147,6 +1149,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, ...@@ -1147,6 +1149,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
modified = true; modified = true;
} }
if (swdev_notify)
fdb->added_by_user = 1;
if (modified) if (modified)
fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify);
} }
......
...@@ -25,6 +25,7 @@ ALL_TESTS=" ...@@ -25,6 +25,7 @@ ALL_TESTS="
lag_unlink_slaves_test lag_unlink_slaves_test
lag_dev_deletion_test lag_dev_deletion_test
vlan_interface_uppers_test vlan_interface_uppers_test
bridge_extern_learn_test
devlink_reload_test devlink_reload_test
" "
NUM_NETIFS=2 NUM_NETIFS=2
...@@ -541,6 +542,25 @@ vlan_interface_uppers_test() ...@@ -541,6 +542,25 @@ vlan_interface_uppers_test()
ip link del dev br0 ip link del dev br0
} }
bridge_extern_learn_test()
{
# Test that externally learned entries added from user space are
# marked as offloaded
RET=0
ip link add name br0 type bridge
ip link set dev $swp1 master br0
bridge fdb add de:ad:be:ef:13:37 dev $swp1 master extern_learn
bridge fdb show brport $swp1 | grep de:ad:be:ef:13:37 | grep -q offload
check_err $? "fdb entry not marked as offloaded when should"
log_test "externally learned fdb entry"
ip link del dev br0
}
devlink_reload_test() devlink_reload_test()
{ {
# Test that after executing all the above configuration tests, a # Test that after executing all the above configuration tests, a
......
#!/bin/bash #!/bin/bash
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding vlan_deletion" ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding vlan_deletion extern_learn"
NUM_NETIFS=4 NUM_NETIFS=4
CHECK_TC="yes" CHECK_TC="yes"
source lib.sh source lib.sh
...@@ -109,6 +109,38 @@ vlan_deletion() ...@@ -109,6 +109,38 @@ vlan_deletion()
ping_ipv6 ping_ipv6
} }
extern_learn()
{
local mac=de:ad:be:ef:13:37
local ageing_time
# Test that externally learned FDB entries can roam, but not age out
RET=0
bridge fdb add de:ad:be:ef:13:37 dev $swp1 master extern_learn vlan 1
bridge fdb show brport $swp1 | grep -q de:ad:be:ef:13:37
check_err $? "Did not find FDB entry when should"
# Wait for 10 seconds after the ageing time to make sure the FDB entry
# was not aged out
ageing_time=$(bridge_ageing_time_get br0)
sleep $((ageing_time + 10))
bridge fdb show brport $swp1 | grep -q de:ad:be:ef:13:37
check_err $? "FDB entry was aged out when should not"
$MZ $h2 -c 1 -p 64 -a $mac -t ip -q
bridge fdb show brport $swp2 | grep -q de:ad:be:ef:13:37
check_err $? "FDB entry did not roam when should"
log_test "Externally learned FDB entry - ageing & roaming"
bridge fdb del de:ad:be:ef:13:37 dev $swp2 master vlan 1 &> /dev/null
bridge fdb del de:ad:be:ef:13:37 dev $swp1 master vlan 1 &> /dev/null
}
trap cleanup EXIT trap cleanup EXIT
setup_prepare setup_prepare
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment