From 29109f495f5842f4e9a09ffb54ae3e13298fff07 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 2 Aug 2019 22:25:27 +0100 Subject: [PATCH 749/773] net: bcmgenet: Workaround for Pi 4B network issue Some combinations of Pi 4Bs and Ethernet switches don't reliably get a DCHP-assigned IP address, leaving the unit with a self=assigned 169.254 address. Forcing renegotiation has been found to be an effective workaround, so add an automatic renegotiation after the link comes up for the first time; enable it with genet.force_reneg=y - by default it is disabled. See: https://github.com/raspberrypi/linux/issues/3108 Signed-off-by: Phil Elwell --- .../net/ethernet/broadcom/genet/bcmgenet.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -72,6 +72,10 @@ #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \ TOTAL_DESC * DMA_DESC_SIZE) +static bool force_reneg = false; +module_param(force_reneg, bool, 0444); +MODULE_PARM_DESC(force_reneg, "Force a renegotiation after the initial link-up"); + static inline void bcmgenet_writel(u32 value, void __iomem *offset) { /* MIPS chips strapped for BE will automagically configure the @@ -2610,6 +2614,7 @@ static void bcmgenet_irq_task(struct wor unsigned int status; struct bcmgenet_priv *priv = container_of( work, struct bcmgenet_priv, bcmgenet_irq_work); + static int first_link = 1; netif_dbg(priv, intr, priv->dev, "%s\n", __func__); @@ -2622,6 +2627,23 @@ static void bcmgenet_irq_task(struct wor if (status & UMAC_IRQ_LINK_EVENT) { priv->dev->phydev->link = !!(status & UMAC_IRQ_LINK_UP); phy_mac_interrupt(priv->dev->phydev); + + if (priv->dev->phydev->link && first_link) { + first_link = 0; + /* + * HACK: Some Pi4Bs, when paired with some switches, + * come up in a strange state where they are unable to + * transmit, causing them to fail to get an IP address. + * Although the failure mechanism is not yet understood, + * forcing renegotiation at this point has been shown + * to be effective in avoiding the problem. + */ + if (force_reneg) { + dev_info(&priv->pdev->dev, + "Forcing renegotiation\n"); + genphy_restart_aneg(priv->dev->phydev); + } + } } }