net: bcmgenet: synchronize irq0 status between the isr and task
Add a spinlock to ensure that irq0_stat is not unintentionally altered
as the result of preemption. Also removed unserviced irq0 interrupts
and removed irq1_stat since there is no bottom half service for those
interrupts.
Fixes: 1c1008c793
("net: bcmgenet: add main driver file")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
7627409cc4
Коммит
07c52d6a0b
|
@ -2506,24 +2506,28 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
|
||||||
/* Interrupt bottom half */
|
/* Interrupt bottom half */
|
||||||
static void bcmgenet_irq_task(struct work_struct *work)
|
static void bcmgenet_irq_task(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int status;
|
||||||
struct bcmgenet_priv *priv = container_of(
|
struct bcmgenet_priv *priv = container_of(
|
||||||
work, struct bcmgenet_priv, bcmgenet_irq_work);
|
work, struct bcmgenet_priv, bcmgenet_irq_work);
|
||||||
|
|
||||||
netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
|
netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
|
||||||
|
|
||||||
if (priv->irq0_stat & UMAC_IRQ_MPD_R) {
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
priv->irq0_stat &= ~UMAC_IRQ_MPD_R;
|
status = priv->irq0_stat;
|
||||||
|
priv->irq0_stat = 0;
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
|
if (status & UMAC_IRQ_MPD_R) {
|
||||||
netif_dbg(priv, wol, priv->dev,
|
netif_dbg(priv, wol, priv->dev,
|
||||||
"magic packet detected, waking up\n");
|
"magic packet detected, waking up\n");
|
||||||
bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
|
bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Link UP/DOWN event */
|
/* Link UP/DOWN event */
|
||||||
if (priv->irq0_stat & UMAC_IRQ_LINK_EVENT) {
|
if (status & UMAC_IRQ_LINK_EVENT)
|
||||||
phy_mac_interrupt(priv->phydev,
|
phy_mac_interrupt(priv->phydev,
|
||||||
!!(priv->irq0_stat & UMAC_IRQ_LINK_UP));
|
!!(status & UMAC_IRQ_LINK_UP));
|
||||||
priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bcmgenet_isr1: handle Rx and Tx priority queues */
|
/* bcmgenet_isr1: handle Rx and Tx priority queues */
|
||||||
|
@ -2532,22 +2536,21 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
|
||||||
struct bcmgenet_priv *priv = dev_id;
|
struct bcmgenet_priv *priv = dev_id;
|
||||||
struct bcmgenet_rx_ring *rx_ring;
|
struct bcmgenet_rx_ring *rx_ring;
|
||||||
struct bcmgenet_tx_ring *tx_ring;
|
struct bcmgenet_tx_ring *tx_ring;
|
||||||
unsigned int index;
|
unsigned int index, status;
|
||||||
|
|
||||||
/* Save irq status for bottom-half processing. */
|
/* Read irq status */
|
||||||
priv->irq1_stat =
|
status = bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
|
||||||
bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
|
|
||||||
~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
|
~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS);
|
||||||
|
|
||||||
/* clear interrupts */
|
/* clear interrupts */
|
||||||
bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
|
bcmgenet_intrl2_1_writel(priv, status, INTRL2_CPU_CLEAR);
|
||||||
|
|
||||||
netif_dbg(priv, intr, priv->dev,
|
netif_dbg(priv, intr, priv->dev,
|
||||||
"%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
|
"%s: IRQ=0x%x\n", __func__, status);
|
||||||
|
|
||||||
/* Check Rx priority queue interrupts */
|
/* Check Rx priority queue interrupts */
|
||||||
for (index = 0; index < priv->hw_params->rx_queues; index++) {
|
for (index = 0; index < priv->hw_params->rx_queues; index++) {
|
||||||
if (!(priv->irq1_stat & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
|
if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rx_ring = &priv->rx_rings[index];
|
rx_ring = &priv->rx_rings[index];
|
||||||
|
@ -2560,7 +2563,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
|
||||||
|
|
||||||
/* Check Tx priority queue interrupts */
|
/* Check Tx priority queue interrupts */
|
||||||
for (index = 0; index < priv->hw_params->tx_queues; index++) {
|
for (index = 0; index < priv->hw_params->tx_queues; index++) {
|
||||||
if (!(priv->irq1_stat & BIT(index)))
|
if (!(status & BIT(index)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tx_ring = &priv->tx_rings[index];
|
tx_ring = &priv->tx_rings[index];
|
||||||
|
@ -2580,19 +2583,20 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
||||||
struct bcmgenet_priv *priv = dev_id;
|
struct bcmgenet_priv *priv = dev_id;
|
||||||
struct bcmgenet_rx_ring *rx_ring;
|
struct bcmgenet_rx_ring *rx_ring;
|
||||||
struct bcmgenet_tx_ring *tx_ring;
|
struct bcmgenet_tx_ring *tx_ring;
|
||||||
|
unsigned int status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* Save irq status for bottom-half processing. */
|
/* Read irq status */
|
||||||
priv->irq0_stat =
|
status = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
|
||||||
bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
|
|
||||||
~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
|
~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
|
||||||
|
|
||||||
/* clear interrupts */
|
/* clear interrupts */
|
||||||
bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
|
bcmgenet_intrl2_0_writel(priv, status, INTRL2_CPU_CLEAR);
|
||||||
|
|
||||||
netif_dbg(priv, intr, priv->dev,
|
netif_dbg(priv, intr, priv->dev,
|
||||||
"IRQ=0x%x\n", priv->irq0_stat);
|
"IRQ=0x%x\n", status);
|
||||||
|
|
||||||
if (priv->irq0_stat & UMAC_IRQ_RXDMA_DONE) {
|
if (status & UMAC_IRQ_RXDMA_DONE) {
|
||||||
rx_ring = &priv->rx_rings[DESC_INDEX];
|
rx_ring = &priv->rx_rings[DESC_INDEX];
|
||||||
|
|
||||||
if (likely(napi_schedule_prep(&rx_ring->napi))) {
|
if (likely(napi_schedule_prep(&rx_ring->napi))) {
|
||||||
|
@ -2601,7 +2605,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->irq0_stat & UMAC_IRQ_TXDMA_DONE) {
|
if (status & UMAC_IRQ_TXDMA_DONE) {
|
||||||
tx_ring = &priv->tx_rings[DESC_INDEX];
|
tx_ring = &priv->tx_rings[DESC_INDEX];
|
||||||
|
|
||||||
if (likely(napi_schedule_prep(&tx_ring->napi))) {
|
if (likely(napi_schedule_prep(&tx_ring->napi))) {
|
||||||
|
@ -2610,20 +2614,21 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
|
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
|
||||||
UMAC_IRQ_PHY_DET_F |
|
status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
|
||||||
UMAC_IRQ_LINK_EVENT |
|
wake_up(&priv->wq);
|
||||||
UMAC_IRQ_HFB_SM |
|
|
||||||
UMAC_IRQ_HFB_MM |
|
|
||||||
UMAC_IRQ_MPD_R)) {
|
|
||||||
/* all other interested interrupts handled in bottom half */
|
|
||||||
schedule_work(&priv->bcmgenet_irq_work);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
|
/* all other interested interrupts handled in bottom half */
|
||||||
priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
|
status &= (UMAC_IRQ_LINK_EVENT |
|
||||||
priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
|
UMAC_IRQ_MPD_R);
|
||||||
wake_up(&priv->wq);
|
if (status) {
|
||||||
|
/* Save irq status for bottom-half processing. */
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
priv->irq0_stat |= status;
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
|
schedule_work(&priv->bcmgenet_irq_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -3327,6 +3332,8 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||||
dev_set_drvdata(&pdev->dev, dev);
|
dev_set_drvdata(&pdev->dev, dev);
|
||||||
ether_addr_copy(dev->dev_addr, macaddr);
|
ether_addr_copy(dev->dev_addr, macaddr);
|
||||||
|
|
|
@ -623,11 +623,13 @@ struct bcmgenet_priv {
|
||||||
struct work_struct bcmgenet_irq_work;
|
struct work_struct bcmgenet_irq_work;
|
||||||
int irq0;
|
int irq0;
|
||||||
int irq1;
|
int irq1;
|
||||||
unsigned int irq0_stat;
|
|
||||||
unsigned int irq1_stat;
|
|
||||||
int wol_irq;
|
int wol_irq;
|
||||||
bool wol_irq_disabled;
|
bool wol_irq_disabled;
|
||||||
|
|
||||||
|
/* shared status */
|
||||||
|
spinlock_t lock;
|
||||||
|
unsigned int irq0_stat;
|
||||||
|
|
||||||
/* HW descriptors/checksum variables */
|
/* HW descriptors/checksum variables */
|
||||||
bool desc_64b_en;
|
bool desc_64b_en;
|
||||||
bool desc_rxchk_en;
|
bool desc_rxchk_en;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче