Commit df934abb authored by David Thompson's avatar David Thompson Committed by Paolo Abeni

mlxbf_gige: disable RX filters until RX path initialized

A recent change to the driver exposed a bug where the MAC RX
filters (unicast MAC, broadcast MAC, and multicast MAC) are
configured and enabled before the RX path is fully initialized.
The result of this bug is that after the PHY is started packets
that match these MAC RX filters start to flow into the RX FIFO.
And then, after rx_init() is completed, these packets will go
into the driver RX ring as well. If enough packets are received
to fill the RX ring (default size is 128 packets) before the call
to request_irq() completes, the driver RX function becomes stuck.

This bug is intermittent but is most likely to be seen where the
oob_net0 interface is connected to a busy network with lots of
broadcast and multicast traffic.

All the MAC RX filters must be disabled until the RX path is ready,
i.e. all initialization is done and all the IRQs are installed.

Fixes: f7442a63 ("mlxbf_gige: call request_irq() after NAPI initialized")
Reviewed-by: default avatarAsmaa Mnebhi <asmaa@nvidia.com>
Signed-off-by: default avatarDavid Thompson <davthompson@nvidia.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20240809163612.12852-1-davthompson@nvidia.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 58a63729
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
*/ */
#define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0 #define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0
#define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1 #define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1
#define MLXBF_GIGE_MAX_FILTER_IDX 3
/* Define for broadcast MAC literal */ /* Define for broadcast MAC literal */
#define BCAST_MAC_ADDR 0xFFFFFFFFFFFF #define BCAST_MAC_ADDR 0xFFFFFFFFFFFF
...@@ -175,6 +176,13 @@ enum mlxbf_gige_res { ...@@ -175,6 +176,13 @@ enum mlxbf_gige_res {
int mlxbf_gige_mdio_probe(struct platform_device *pdev, int mlxbf_gige_mdio_probe(struct platform_device *pdev,
struct mlxbf_gige *priv); struct mlxbf_gige *priv);
void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv);
void mlxbf_gige_enable_multicast_rx(struct mlxbf_gige *priv);
void mlxbf_gige_disable_multicast_rx(struct mlxbf_gige *priv);
void mlxbf_gige_enable_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index);
void mlxbf_gige_disable_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index);
void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index, u64 dmac); unsigned int index, u64 dmac);
void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
......
...@@ -168,6 +168,10 @@ static int mlxbf_gige_open(struct net_device *netdev) ...@@ -168,6 +168,10 @@ static int mlxbf_gige_open(struct net_device *netdev)
if (err) if (err)
goto napi_deinit; goto napi_deinit;
mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX);
mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX);
mlxbf_gige_enable_multicast_rx(priv);
/* Set bits in INT_EN that we care about */ /* Set bits in INT_EN that we care about */
int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR |
MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS | MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS |
...@@ -379,6 +383,7 @@ static int mlxbf_gige_probe(struct platform_device *pdev) ...@@ -379,6 +383,7 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
void __iomem *plu_base; void __iomem *plu_base;
void __iomem *base; void __iomem *base;
int addr, phy_irq; int addr, phy_irq;
unsigned int i;
int err; int err;
base = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MAC); base = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MAC);
...@@ -423,6 +428,11 @@ static int mlxbf_gige_probe(struct platform_device *pdev) ...@@ -423,6 +428,11 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ;
priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ;
for (i = 0; i <= MLXBF_GIGE_MAX_FILTER_IDX; i++)
mlxbf_gige_disable_mac_rx_filter(priv, i);
mlxbf_gige_disable_multicast_rx(priv);
mlxbf_gige_disable_promisc(priv);
/* Write initial MAC address to hardware */ /* Write initial MAC address to hardware */
mlxbf_gige_initial_mac(priv); mlxbf_gige_initial_mac(priv);
......
...@@ -62,6 +62,8 @@ ...@@ -62,6 +62,8 @@
#define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1) #define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1)
#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520 #define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520
#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528 #define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528
#define MLXBF_GIGE_RX_MAC_FILTER_GENERAL 0x0530
#define MLXBF_GIGE_RX_MAC_FILTER_EN_MULTICAST BIT(1)
#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540 #define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540
#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0) #define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0)
#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548 #define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548
......
...@@ -11,15 +11,31 @@ ...@@ -11,15 +11,31 @@
#include "mlxbf_gige.h" #include "mlxbf_gige.h"
#include "mlxbf_gige_regs.h" #include "mlxbf_gige_regs.h"
void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, void mlxbf_gige_enable_multicast_rx(struct mlxbf_gige *priv)
unsigned int index, u64 dmac)
{ {
void __iomem *base = priv->base; void __iomem *base = priv->base;
u64 control; u64 data;
/* Write destination MAC to specified MAC RX filter */ data = readq(base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + data |= MLXBF_GIGE_RX_MAC_FILTER_EN_MULTICAST;
(index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); writeq(data, base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
}
void mlxbf_gige_disable_multicast_rx(struct mlxbf_gige *priv)
{
void __iomem *base = priv->base;
u64 data;
data = readq(base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
data &= ~MLXBF_GIGE_RX_MAC_FILTER_EN_MULTICAST;
writeq(data, base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
}
void mlxbf_gige_enable_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index)
{
void __iomem *base = priv->base;
u64 control;
/* Enable MAC receive filter mask for specified index */ /* Enable MAC receive filter mask for specified index */
control = readq(base + MLXBF_GIGE_CONTROL); control = readq(base + MLXBF_GIGE_CONTROL);
...@@ -27,6 +43,28 @@ void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, ...@@ -27,6 +43,28 @@ void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
writeq(control, base + MLXBF_GIGE_CONTROL); writeq(control, base + MLXBF_GIGE_CONTROL);
} }
void mlxbf_gige_disable_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index)
{
void __iomem *base = priv->base;
u64 control;
/* Disable MAC receive filter mask for specified index */
control = readq(base + MLXBF_GIGE_CONTROL);
control &= ~(MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index);
writeq(control, base + MLXBF_GIGE_CONTROL);
}
void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index, u64 dmac)
{
void __iomem *base = priv->base;
/* Write destination MAC to specified MAC RX filter */
writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER +
(index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE));
}
void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index, u64 *dmac) unsigned int index, u64 *dmac)
{ {
......
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