igb: reduce cache misses on tx cleanup
This patch reduces the number of skb cache misses in the clean_tx_irq path, and results in an overall increase in tx packet throughput. Signed-off-by: Nicholas Nunley <nicholasx.d.nunley@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
a84afa40e0
commit
2873957df0
@@ -141,8 +141,10 @@ struct igb_buffer {
|
|||||||
unsigned long time_stamp;
|
unsigned long time_stamp;
|
||||||
u16 length;
|
u16 length;
|
||||||
u16 next_to_watch;
|
u16 next_to_watch;
|
||||||
u16 mapped_as_page;
|
unsigned int bytecount;
|
||||||
u16 gso_segs;
|
u16 gso_segs;
|
||||||
|
union skb_shared_tx shtx;
|
||||||
|
u8 mapped_as_page;
|
||||||
};
|
};
|
||||||
/* RX */
|
/* RX */
|
||||||
struct {
|
struct {
|
||||||
|
@@ -3899,34 +3899,33 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
|
|||||||
{
|
{
|
||||||
struct igb_buffer *buffer_info;
|
struct igb_buffer *buffer_info;
|
||||||
struct device *dev = tx_ring->dev;
|
struct device *dev = tx_ring->dev;
|
||||||
unsigned int len = skb_headlen(skb);
|
unsigned int hlen = skb_headlen(skb);
|
||||||
unsigned int count = 0, i;
|
unsigned int count = 0, i;
|
||||||
unsigned int f;
|
unsigned int f;
|
||||||
|
u16 gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
|
||||||
|
|
||||||
i = tx_ring->next_to_use;
|
i = tx_ring->next_to_use;
|
||||||
|
|
||||||
buffer_info = &tx_ring->buffer_info[i];
|
buffer_info = &tx_ring->buffer_info[i];
|
||||||
BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
|
BUG_ON(hlen >= IGB_MAX_DATA_PER_TXD);
|
||||||
buffer_info->length = len;
|
buffer_info->length = hlen;
|
||||||
/* set time_stamp *before* dma to help avoid a possible race */
|
/* set time_stamp *before* dma to help avoid a possible race */
|
||||||
buffer_info->time_stamp = jiffies;
|
buffer_info->time_stamp = jiffies;
|
||||||
buffer_info->next_to_watch = i;
|
buffer_info->next_to_watch = i;
|
||||||
buffer_info->dma = dma_map_single(dev, skb->data, len,
|
buffer_info->dma = dma_map_single(dev, skb->data, hlen,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
if (dma_mapping_error(dev, buffer_info->dma))
|
if (dma_mapping_error(dev, buffer_info->dma))
|
||||||
goto dma_error;
|
goto dma_error;
|
||||||
|
|
||||||
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
|
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
|
||||||
struct skb_frag_struct *frag;
|
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f];
|
||||||
|
unsigned int len = frag->size;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
i++;
|
i++;
|
||||||
if (i == tx_ring->count)
|
if (i == tx_ring->count)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
frag = &skb_shinfo(skb)->frags[f];
|
|
||||||
len = frag->size;
|
|
||||||
|
|
||||||
buffer_info = &tx_ring->buffer_info[i];
|
buffer_info = &tx_ring->buffer_info[i];
|
||||||
BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
|
BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
|
||||||
buffer_info->length = len;
|
buffer_info->length = len;
|
||||||
@@ -3944,7 +3943,10 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_ring->buffer_info[i].skb = skb;
|
tx_ring->buffer_info[i].skb = skb;
|
||||||
tx_ring->buffer_info[i].gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
|
tx_ring->buffer_info[i].shtx = skb_shinfo(skb)->tx_flags;
|
||||||
|
/* multiply data chunks by size of headers */
|
||||||
|
tx_ring->buffer_info[i].bytecount = ((gso_segs - 1) * hlen) + skb->len;
|
||||||
|
tx_ring->buffer_info[i].gso_segs = gso_segs;
|
||||||
tx_ring->buffer_info[first].next_to_watch = i;
|
tx_ring->buffer_info[first].next_to_watch = i;
|
||||||
|
|
||||||
return ++count;
|
return ++count;
|
||||||
@@ -5288,22 +5290,21 @@ static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
|
|||||||
/**
|
/**
|
||||||
* igb_tx_hwtstamp - utility function which checks for TX time stamp
|
* igb_tx_hwtstamp - utility function which checks for TX time stamp
|
||||||
* @q_vector: pointer to q_vector containing needed info
|
* @q_vector: pointer to q_vector containing needed info
|
||||||
* @skb: packet that was just sent
|
* @buffer: pointer to igb_buffer structure
|
||||||
*
|
*
|
||||||
* If we were asked to do hardware stamping and such a time stamp is
|
* If we were asked to do hardware stamping and such a time stamp is
|
||||||
* available, then it must have been for this skb here because we only
|
* available, then it must have been for this skb here because we only
|
||||||
* allow only one such packet into the queue.
|
* allow only one such packet into the queue.
|
||||||
*/
|
*/
|
||||||
static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb)
|
static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *buffer_info)
|
||||||
{
|
{
|
||||||
struct igb_adapter *adapter = q_vector->adapter;
|
struct igb_adapter *adapter = q_vector->adapter;
|
||||||
union skb_shared_tx *shtx = skb_tx(skb);
|
|
||||||
struct e1000_hw *hw = &adapter->hw;
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
struct skb_shared_hwtstamps shhwtstamps;
|
struct skb_shared_hwtstamps shhwtstamps;
|
||||||
u64 regval;
|
u64 regval;
|
||||||
|
|
||||||
/* if skb does not support hw timestamp or TX stamp not valid exit */
|
/* if skb does not support hw timestamp or TX stamp not valid exit */
|
||||||
if (likely(!shtx->hardware) ||
|
if (likely(!buffer_info->shtx.hardware) ||
|
||||||
!(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
|
!(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -5311,7 +5312,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb)
|
|||||||
regval |= (u64)rd32(E1000_TXSTMPH) << 32;
|
regval |= (u64)rd32(E1000_TXSTMPH) << 32;
|
||||||
|
|
||||||
igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
|
igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
|
||||||
skb_tstamp_tx(skb, &shhwtstamps);
|
skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5326,7 +5327,6 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
|
|||||||
struct net_device *netdev = tx_ring->netdev;
|
struct net_device *netdev = tx_ring->netdev;
|
||||||
struct e1000_hw *hw = &adapter->hw;
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
struct igb_buffer *buffer_info;
|
struct igb_buffer *buffer_info;
|
||||||
struct sk_buff *skb;
|
|
||||||
union e1000_adv_tx_desc *tx_desc, *eop_desc;
|
union e1000_adv_tx_desc *tx_desc, *eop_desc;
|
||||||
unsigned int total_bytes = 0, total_packets = 0;
|
unsigned int total_bytes = 0, total_packets = 0;
|
||||||
unsigned int i, eop, count = 0;
|
unsigned int i, eop, count = 0;
|
||||||
@@ -5342,19 +5342,12 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
|
|||||||
tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
|
tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
|
||||||
buffer_info = &tx_ring->buffer_info[i];
|
buffer_info = &tx_ring->buffer_info[i];
|
||||||
cleaned = (i == eop);
|
cleaned = (i == eop);
|
||||||
skb = buffer_info->skb;
|
|
||||||
|
|
||||||
if (skb) {
|
if (buffer_info->skb) {
|
||||||
unsigned int segs, bytecount;
|
total_bytes += buffer_info->bytecount;
|
||||||
/* gso_segs is currently only valid for tcp */
|
/* gso_segs is currently only valid for tcp */
|
||||||
segs = buffer_info->gso_segs;
|
total_packets += buffer_info->gso_segs;
|
||||||
/* multiply data chunks by size of headers */
|
igb_tx_hwtstamp(q_vector, buffer_info);
|
||||||
bytecount = ((segs - 1) * skb_headlen(skb)) +
|
|
||||||
skb->len;
|
|
||||||
total_packets += segs;
|
|
||||||
total_bytes += bytecount;
|
|
||||||
|
|
||||||
igb_tx_hwtstamp(q_vector, skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
|
igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
|
||||||
|
Reference in New Issue
Block a user