diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3d5c251..152774f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -129,7 +129,10 @@ static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv, #define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x" #define GENET_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ - NETIF_MSG_LINK) + NETIF_MSG_LINK | NETIF_MSG_INTR | \ + NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS | \ + NETIF_MSG_TX_ERR | NETIF_MSG_TX_DONE | \ + NETIF_MSG_IFUP | NETIF_MSG_IFDOWN) static inline u32 bcmgenet_rbuf_ctrl_get(struct bcmgenet_priv *priv) { @@ -3255,24 +3258,58 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) return IRQ_HANDLED; } +struct rbuf_ovfl_work_struct { + struct delayed_work queue; + struct bcmgenet_priv *priv; +} rbuf_ovfl_work; + +static void rbuf_ovfl_wq_func(struct work_struct *work) { + struct delayed_work *dwork = to_delayed_work(work); + struct rbuf_ovfl_work_struct *rbo_work = container_of(dwork, struct rbuf_ovfl_work_struct, queue); + struct bcmgenet_priv *priv = rbo_work->priv; + + unsigned int flags = dev_get_flags(priv->dev); + + rtnl_lock(); + netif_carrier_off(priv->dev); + dev_change_flags(priv->dev, flags & ~IFF_UP); + rtnl_unlock(); + + msleep(1000); + + rtnl_lock(); + dev_change_flags(priv->dev, flags | IFF_UP); + rtnl_unlock(); + + return; +} + /* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; struct bcmgenet_rx_ring *rx_ring; struct bcmgenet_tx_ring *tx_ring; - unsigned int status; + unsigned int status, status_unmask; unsigned long flags; /* Read irq status */ - status = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) & - ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + status_unmask = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); + status = status_unmask & ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + + if (status_unmask & (UMAC_IRQ_RBUF_OVERFLOW)) { + netdev_info(priv->dev, + "%s: %d pkts\n", __func__, bcmgenet_rbuf_readl(priv, RBUF_OVFL_CNT_V3PLUS)); + status |= UMAC_IRQ_RBUF_OVERFLOW; + schedule_delayed_work(&(rbuf_ovfl_work.queue), HZ); + } /* clear interrupts */ bcmgenet_intrl2_0_writel(priv, status, INTRL2_CPU_CLEAR); - netif_dbg(priv, intr, priv->dev, - "IRQ=0x%x\n", status); + if (status & ~(UMAC_IRQ_MDIO_DONE)) /* except for mdio event */ + netif_dbg(priv, intr, priv->dev, + "%s: IRQ=0x%x\n", __func__, status); if (status & UMAC_IRQ_RXDMA_DONE) { rx_ring = &priv->rx_rings[DESC_INDEX]; @@ -3281,6 +3318,10 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) rx_ring->int_disable(rx_ring); __napi_schedule(&rx_ring->napi); } + else { + netif_dbg(priv, intr, priv->dev, + "%s: rx not sched. state=0x%08lx\n", __func__, rx_ring->napi.state); + } } if (status & UMAC_IRQ_TXDMA_DONE) { @@ -3306,6 +3347,8 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) spin_unlock_irqrestore(&priv->lock, flags); schedule_work(&priv->bcmgenet_irq_work); + netif_dbg(priv, intr, priv->dev, + "%s: link event. status=0x%08x\n", __func__, status); } return IRQ_HANDLED; @@ -3351,6 +3394,20 @@ static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) udelay(10); } +static void bcmgenet_rbuf_reset(struct bcmgenet_priv *priv) +{ + u32 reg; + + reg = bcmgenet_rbuf_ctrl_get(priv); + reg |= BIT(0); + bcmgenet_rbuf_ctrl_set(priv, reg); + udelay(100); + + reg &= ~BIT(0); + bcmgenet_rbuf_ctrl_set(priv, reg); + udelay(100); +} + static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, unsigned char *addr) { @@ -3434,6 +3491,7 @@ static int bcmgenet_open(struct net_device *dev) /* take MAC out of reset */ bcmgenet_umac_reset(priv); + bcmgenet_rbuf_reset(priv); ret = init_umac(priv); if (ret) @@ -4070,6 +4128,8 @@ static int bcmgenet_probe(struct platform_device *pdev) /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */ priv->rx_buf_len = RX_BUF_LENGTH; INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); + rbuf_ovfl_work.priv = priv; + INIT_DELAYED_WORK(&(rbuf_ovfl_work.queue), rbuf_ovfl_wq_func); priv->clk_wol = devm_clk_get(&priv->pdev->dev, "sw_genetwol"); if (IS_ERR(priv->clk_wol)) {