You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.5 KiB
138 lines
4.5 KiB
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)) {
|
|
|