Skip to content

Commit

Permalink
amd-xgbe: Remove need for Tx path spinlock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lendacky, Thomas authored and David S. Miller committed Jan 17, 2015
1 parent 270894e commit a83ef42
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 28 deletions.
17 changes: 9 additions & 8 deletions drivers/net/ethernet/amd/xgbe/xgbe-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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 */
Expand Down Expand Up @@ -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)))
Expand Down
21 changes: 1 addition & 20 deletions drivers/net/ethernet/amd/xgbe/xgbe-drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand Down

0 comments on commit a83ef42

Please sign in to comment.