Commit a83ef427 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Remove need for Tx path spinlock

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: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 270894e7
......@@ -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)))
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment