amd-xgbe: Remove need for Tx path spinlock
authorLendacky, Thomas <Thomas.Lendacky@amd.com>
Fri, 16 Jan 2015 18:46:55 +0000 (12:46 -0600)
committerDavid S. Miller <davem@davemloft.net>
Sat, 17 Jan 2015 03:24:20 +0000 (22:24 -0500)
Since the Tx ring cleanup can run at the same time that data is being
transmitted, a spin lock was used to protect the ring. This patch
eliminates the need for Tx spinlocks by updating the current ring
position only after all ownership bits for data being transmitted have
been set. This will insure that ring operations in the Tx cleanup path
do not interfere with the ring operations in the Tx transmit path.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c

index e424997..5dff127 100644 (file)
@@ -1359,6 +1359,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
        unsigned int tso_context, vlan_context;
        unsigned int tx_set_ic;
        int start_index = ring->cur;
+       int cur_index = ring->cur;
        int i;
 
        DBGPR("-->xgbe_dev_xmit\n");
@@ -1401,7 +1402,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
        else
                tx_set_ic = 0;
 
-       rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+       rdata = XGBE_GET_DESC_DATA(ring, cur_index);
        rdesc = rdata->rdesc;
 
        /* Create a context descriptor if this is a TSO packet */
@@ -1444,8 +1445,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
                        ring->tx.cur_vlan_ctag = packet->vlan_ctag;
                }
 
-               ring->cur++;
-               rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+               cur_index++;
+               rdata = XGBE_GET_DESC_DATA(ring, cur_index);
                rdesc = rdata->rdesc;
        }
 
@@ -1473,7 +1474,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
        XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0);
 
        /* Set OWN bit if not the first descriptor */
-       if (ring->cur != start_index)
+       if (cur_index != start_index)
                XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
 
        if (tso) {
@@ -1497,9 +1498,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
                                  packet->length);
        }
 
-       for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) {
-               ring->cur++;
-               rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+       for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) {
+               cur_index++;
+               rdata = XGBE_GET_DESC_DATA(ring, cur_index);
                rdesc = rdata->rdesc;
 
                /* Update buffer address */
@@ -1551,7 +1552,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
        /* Make sure ownership is written to the descriptor */
        wmb();
 
-       ring->cur++;
+       ring->cur = cur_index + 1;
        if (!packet->skb->xmit_more ||
            netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev,
                                                   channel->queue_index)))
index e2f560f..c036a0e 100644 (file)
@@ -415,17 +415,13 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer)
        struct xgbe_channel *channel = container_of(timer,
                                                    struct xgbe_channel,
                                                    tx_timer);
-       struct xgbe_ring *ring = channel->tx_ring;
        struct xgbe_prv_data *pdata = channel->pdata;
        struct napi_struct *napi;
-       unsigned long flags;
 
        DBGPR("-->xgbe_tx_timer\n");
 
        napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
 
-       spin_lock_irqsave(&ring->lock, flags);
-
        if (napi_schedule_prep(napi)) {
                /* Disable Tx and Rx interrupts */
                if (pdata->per_channel_irq)
@@ -439,8 +435,6 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer)
 
        channel->tx_timer_active = 0;
 
-       spin_unlock_irqrestore(&ring->lock, flags);
-
        DBGPR("<--xgbe_tx_timer\n");
 
        return HRTIMER_NORESTART;
@@ -1450,7 +1444,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
        struct xgbe_ring *ring;
        struct xgbe_packet_data *packet;
        struct netdev_queue *txq;
-       unsigned long flags;
        int ret;
 
        DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len);
@@ -1462,8 +1455,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        ret = NETDEV_TX_OK;
 
-       spin_lock_irqsave(&ring->lock, flags);
-
        if (skb->len == 0) {
                netdev_err(netdev, "empty skb received from stack\n");
                dev_kfree_skb_any(skb);
@@ -1510,10 +1501,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
        ret = NETDEV_TX_OK;
 
 tx_netdev_return:
-       spin_unlock_irqrestore(&ring->lock, flags);
-
-       DBGPR("<--xgbe_xmit\n");
-
        return ret;
 }
 
@@ -1841,7 +1828,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
        struct xgbe_ring_desc *rdesc;
        struct net_device *netdev = pdata->netdev;
        struct netdev_queue *txq;
-       unsigned long flags;
        int processed = 0;
        unsigned int tx_packets = 0, tx_bytes = 0;
 
@@ -1853,8 +1839,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
 
        txq = netdev_get_tx_queue(netdev, channel->queue_index);
 
-       spin_lock_irqsave(&ring->lock, flags);
-
        while ((processed < XGBE_TX_DESC_MAX_PROC) &&
               (ring->dirty != ring->cur)) {
                rdata = XGBE_GET_DESC_DATA(ring, ring->dirty);
@@ -1885,7 +1869,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
        }
 
        if (!processed)
-               goto unlock;
+               return 0;
 
        netdev_tx_completed_queue(txq, tx_packets, tx_bytes);
 
@@ -1897,9 +1881,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
 
        DBGPR("<--xgbe_tx_poll: processed=%d\n", processed);
 
-unlock:
-       spin_unlock_irqrestore(&ring->lock, flags);
-
        return processed;
 }