From d8498088cf466483093c9a29121e3833e7923287 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Jun 2014 10:22:15 -0700 Subject: [PATCH 1/4] net: systemport: fix transmit locking scheme Our transmit locking scheme did not account for the TX ring full interrupt. If a TX ring full interrupt fires while we are attempting to transmit, we will cause a deadlock to occur. Fix this by making sure that we properly disable interrupts while acquiring the spinlock. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 25982b02f0ea..4dfc93fe9744 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -637,10 +637,11 @@ static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, struct bcm_sysport_tx_ring *ring) { unsigned int released; + unsigned long flags; - spin_lock(&ring->lock); + spin_lock_irqsave(&ring->lock, flags); released = __bcm_sysport_tx_reclaim(priv, ring); - spin_unlock(&ring->lock); + spin_unlock_irqrestore(&ring->lock, flags); return released; } @@ -822,6 +823,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, struct netdev_queue *txq; struct dma_desc *desc; unsigned int skb_len; + unsigned long flags; dma_addr_t mapping; u32 len_status; u16 queue; @@ -831,8 +833,8 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, txq = netdev_get_tx_queue(dev, queue); ring = &priv->tx_rings[queue]; - /* lock against tx reclaim in BH context */ - spin_lock(&ring->lock); + /* lock against tx reclaim in BH context and TX ring full interrupt */ + spin_lock_irqsave(&ring->lock, flags); if (unlikely(ring->desc_count == 0)) { netif_tx_stop_queue(txq); netdev_err(dev, "queue %d awake and ring full!\n", queue); @@ -914,7 +916,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, ret = NETDEV_TX_OK; out: - spin_unlock(&ring->lock); + spin_unlock_irqrestore(&ring->lock, flags); return ret; } From ad51c6106119adf8565adb179989a06ab4b865bb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Jun 2014 10:22:16 -0700 Subject: [PATCH 2/4] net: systemport: correctly check for RX_STATUS_OVFLOW flag We were missing an and comparison with status to check whether RX_STATUS_OVFLOW is asserted or not in the per-packet status word, fix that. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 4dfc93fe9744..fc84aba0cde0 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -514,7 +514,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, if (unlikely(status & (RX_STATUS_ERR | RX_STATUS_OVFLOW))) { netif_err(priv, rx_err, ndev, "error packet\n"); - if (RX_STATUS_OVFLOW) + if (status & RX_STATUS_OVFLOW) ndev->stats.rx_over_errors++; ndev->stats.rx_dropped++; ndev->stats.rx_errors++; From e0ea05d00b61a12935dfceefb388eadcde31f35a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Jun 2014 10:22:17 -0700 Subject: [PATCH 3/4] net: systemport: fix comment about HW prepending 2bytes The comment about how the hardware prepends 2bytes to align the IP header on a 4-byte boundary was not correct, fix that. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index fc84aba0cde0..54b51db0caf3 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -528,9 +528,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, if (likely(status & DESC_L4_CSUM)) skb->ip_summed = CHECKSUM_UNNECESSARY; - /* Hardware pre-pends packets with 2bytes between Ethernet - * and IP header plus we have the Receive Status Block, strip - * off all of this from the SKB. + /* Hardware pre-pends packets with 2bytes before Ethernet + * header plus we have the Receive Status Block, strip off all + * of this from the SKB. */ skb_pull(skb, sizeof(*rsb) + 2); len -= (sizeof(*rsb) + 2); From f532e744a4693677452da67c48ade5de707f3c1c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Jun 2014 10:22:18 -0700 Subject: [PATCH 4/4] net: systemport: start with carrier off The SYSTEMPORT driver uses libphy to determine the carrier state, so make sure we start with a carrier off until libphy has completed the link training process. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 54b51db0caf3..141160ef249a 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1595,6 +1595,9 @@ static int bcm_sysport_probe(struct platform_device *pdev) */ dev->flags &= ~IFF_MULTICAST; + /* libphy will adjust the link state accordingly */ + netif_carrier_off(dev); + ret = register_netdev(dev); if (ret) { dev_err(&pdev->dev, "failed to register net_device\n");