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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
efa8c819a6
|
@ -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,
|
||||||
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 @@
|
||||||
|
|
||||||
#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 @@
|
||||||
#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 = {
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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="
|
||||||
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()
|
||||||
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/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()
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue