mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 08:02:59 -04:00
nfp: prevent dropped counter increment during probe
The dev_rx_discards counter will increment by one when an interface is toggled up and down. The main reason is that the driver first sends a `NFP_NET_CFG_CTRL_ENABLE` configuration packet to the NIC to perform port initialisation when an interface is set up. But there is a race between physical link up and free list queue initialization which may lead to the configuration packet being discarded. To address this problem a new bit NFP_NET_CFG_CTRL_FREELIST_EN is added to perform free list initialisation on the NIC. The FREELIST_EN should be sent in advance to initialize free list queue. When a port is set to down, FREELIST_EN should be sent after CTRL_ENABLE to avoid packet discards. Signed-off-by: Ziyang Chen <ziyang.chen@corigine.com> Acked-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: Louis Peens <louis.peens@corigine.com> Link: https://lore.kernel.org/r/20230712123551.13858-1-louis.peens@corigine.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
6f13b49b57
commit
bec9ce3407
@@ -924,7 +924,7 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *addr)
|
||||
*/
|
||||
static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
|
||||
{
|
||||
u32 new_ctrl, update;
|
||||
u32 new_ctrl, new_ctrl_w1, update;
|
||||
unsigned int r;
|
||||
int err;
|
||||
|
||||
@@ -937,14 +937,29 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
|
||||
if (nn->cap & NFP_NET_CFG_CTRL_RINGCFG)
|
||||
new_ctrl &= ~NFP_NET_CFG_CTRL_RINGCFG;
|
||||
|
||||
nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
|
||||
nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
|
||||
if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN)) {
|
||||
nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
|
||||
nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
|
||||
}
|
||||
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
|
||||
err = nfp_net_reconfig(nn, update);
|
||||
if (err)
|
||||
nn_err(nn, "Could not disable device: %d\n", err);
|
||||
|
||||
if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN) {
|
||||
new_ctrl_w1 = nn->dp.ctrl_w1;
|
||||
new_ctrl_w1 &= ~NFP_NET_CFG_CTRL_FREELIST_EN;
|
||||
nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
|
||||
nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
|
||||
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, new_ctrl_w1);
|
||||
err = nfp_net_reconfig(nn, update);
|
||||
if (err)
|
||||
nn_err(nn, "Could not disable FREELIST_EN: %d\n", err);
|
||||
nn->dp.ctrl_w1 = new_ctrl_w1;
|
||||
}
|
||||
|
||||
for (r = 0; r < nn->dp.num_rx_rings; r++) {
|
||||
nfp_net_rx_ring_reset(&nn->dp.rx_rings[r]);
|
||||
if (nfp_net_has_xsk_pool_slow(&nn->dp, nn->dp.rx_rings[r].idx))
|
||||
@@ -964,11 +979,12 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
|
||||
*/
|
||||
static int nfp_net_set_config_and_enable(struct nfp_net *nn)
|
||||
{
|
||||
u32 bufsz, new_ctrl, update = 0;
|
||||
u32 bufsz, new_ctrl, new_ctrl_w1, update = 0;
|
||||
unsigned int r;
|
||||
int err;
|
||||
|
||||
new_ctrl = nn->dp.ctrl;
|
||||
new_ctrl_w1 = nn->dp.ctrl_w1;
|
||||
|
||||
if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS_ANY) {
|
||||
nfp_net_rss_write_key(nn);
|
||||
@@ -1001,16 +1017,25 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn)
|
||||
bufsz = nn->dp.fl_bufsz - nn->dp.rx_dma_off - NFP_NET_RX_BUF_NON_DATA;
|
||||
nn_writel(nn, NFP_NET_CFG_FLBUFSZ, bufsz);
|
||||
|
||||
/* Enable device */
|
||||
new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
|
||||
/* Enable device
|
||||
* Step 1: Replace the CTRL_ENABLE by NFP_NET_CFG_CTRL_FREELIST_EN if
|
||||
* FREELIST_EN exits.
|
||||
*/
|
||||
if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN)
|
||||
new_ctrl_w1 |= NFP_NET_CFG_CTRL_FREELIST_EN;
|
||||
else
|
||||
new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
|
||||
update |= NFP_NET_CFG_UPDATE_GEN;
|
||||
update |= NFP_NET_CFG_UPDATE_MSIX;
|
||||
update |= NFP_NET_CFG_UPDATE_RING;
|
||||
if (nn->cap & NFP_NET_CFG_CTRL_RINGCFG)
|
||||
new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG;
|
||||
|
||||
/* Step 2: Send the configuration and write the freelist.
|
||||
* - The freelist only need to be written once.
|
||||
*/
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, nn->dp.ctrl_w1);
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, new_ctrl_w1);
|
||||
err = nfp_net_reconfig(nn, update);
|
||||
if (err) {
|
||||
nfp_net_clear_config_and_disable(nn);
|
||||
@@ -1018,10 +1043,25 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn)
|
||||
}
|
||||
|
||||
nn->dp.ctrl = new_ctrl;
|
||||
nn->dp.ctrl_w1 = new_ctrl_w1;
|
||||
|
||||
for (r = 0; r < nn->dp.num_rx_rings; r++)
|
||||
nfp_net_rx_ring_fill_freelist(&nn->dp, &nn->dp.rx_rings[r]);
|
||||
|
||||
/* Step 3: Do the NFP_NET_CFG_CTRL_ENABLE. Send the configuration.
|
||||
*/
|
||||
if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN) {
|
||||
new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
|
||||
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
|
||||
|
||||
err = nfp_net_reconfig(nn, update);
|
||||
if (err) {
|
||||
nfp_net_clear_config_and_disable(nn);
|
||||
return err;
|
||||
}
|
||||
nn->dp.ctrl = new_ctrl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@
|
||||
#define NFP_NET_CFG_CTRL_PKT_TYPE (0x1 << 0) /* Pkttype offload */
|
||||
#define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /* IPsec offload */
|
||||
#define NFP_NET_CFG_CTRL_MCAST_FILTER (0x1 << 2) /* Multicast Filter */
|
||||
#define NFP_NET_CFG_CTRL_FREELIST_EN (0x1 << 6) /* Freelist enable flag bit */
|
||||
|
||||
#define NFP_NET_CFG_CAP_WORD1 0x00a4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user