e1000: Fixes for packet split related issues
Fixes for packet split related issues * On platforms where PAGE_SIZE > 4K, driver will use only required number of pages compared to always using 3 pages. * Packet split won't be used if the PAGE_SIZE is > 16K * Adds a statistics counter to splits. * Setting the non Null ptr to zero sized buffers to solve packet split receive descriptor error * When the no of pages needed is calculated, the header buffer is not included for a given MTU. Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com> Signed-off-by: Ganesh Venkatesan <ganesh.venkatesan@intel.com> Signed-off-by: John Ronciak <john.ronciak@intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
2ae76d98fb
commit
e4c811c9d2
3 changed files with 60 additions and 38 deletions
|
@ -169,8 +169,8 @@ struct e1000_buffer {
|
||||||
uint16_t next_to_watch;
|
uint16_t next_to_watch;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; };
|
struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; };
|
||||||
struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; };
|
struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; };
|
||||||
|
|
||||||
struct e1000_tx_ring {
|
struct e1000_tx_ring {
|
||||||
/* pointer to the descriptor ring memory */
|
/* pointer to the descriptor ring memory */
|
||||||
|
@ -300,10 +300,11 @@ struct e1000_adapter {
|
||||||
|
|
||||||
uint64_t hw_csum_err;
|
uint64_t hw_csum_err;
|
||||||
uint64_t hw_csum_good;
|
uint64_t hw_csum_good;
|
||||||
|
uint64_t rx_hdr_split;
|
||||||
uint32_t rx_int_delay;
|
uint32_t rx_int_delay;
|
||||||
uint32_t rx_abs_int_delay;
|
uint32_t rx_abs_int_delay;
|
||||||
boolean_t rx_csum;
|
boolean_t rx_csum;
|
||||||
boolean_t rx_ps;
|
unsigned int rx_ps_pages;
|
||||||
uint32_t gorcl;
|
uint32_t gorcl;
|
||||||
uint64_t gorcl_old;
|
uint64_t gorcl_old;
|
||||||
uint16_t rx_ps_bsize0;
|
uint16_t rx_ps_bsize0;
|
||||||
|
|
|
@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
|
||||||
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
|
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
|
||||||
{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
|
{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
|
||||||
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
|
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
|
||||||
{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
|
{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
|
||||||
|
{ "rx_header_split", E1000_STAT(rx_hdr_split) },
|
||||||
};
|
};
|
||||||
#define E1000_STATS_LEN \
|
#define E1000_STATS_LEN \
|
||||||
sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
|
sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
|
||||||
|
|
|
@ -1484,12 +1484,16 @@ e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
|
||||||
* e1000_setup_rctl - configure the receive control registers
|
* e1000_setup_rctl - configure the receive control registers
|
||||||
* @adapter: Board private structure
|
* @adapter: Board private structure
|
||||||
**/
|
**/
|
||||||
|
#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
|
||||||
|
(((S) & (PAGE_SIZE - 1)) ? 1 : 0))
|
||||||
static void
|
static void
|
||||||
e1000_setup_rctl(struct e1000_adapter *adapter)
|
e1000_setup_rctl(struct e1000_adapter *adapter)
|
||||||
{
|
{
|
||||||
uint32_t rctl, rfctl;
|
uint32_t rctl, rfctl;
|
||||||
uint32_t psrctl = 0;
|
uint32_t psrctl = 0;
|
||||||
|
#ifdef CONFIG_E1000_PACKET_SPLIT
|
||||||
|
uint32_t pages = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
rctl = E1000_READ_REG(&adapter->hw, RCTL);
|
rctl = E1000_READ_REG(&adapter->hw, RCTL);
|
||||||
|
|
||||||
|
@ -1543,11 +1547,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
|
||||||
* followed by the page buffers. Therefore, skb->data is
|
* followed by the page buffers. Therefore, skb->data is
|
||||||
* sized to hold the largest protocol header.
|
* sized to hold the largest protocol header.
|
||||||
*/
|
*/
|
||||||
adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2)
|
pages = PAGE_USE_COUNT(adapter->netdev->mtu);
|
||||||
&& (adapter->netdev->mtu
|
if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) &&
|
||||||
< ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0));
|
PAGE_SIZE <= 16384)
|
||||||
|
adapter->rx_ps_pages = pages;
|
||||||
|
else
|
||||||
|
adapter->rx_ps_pages = 0;
|
||||||
#endif
|
#endif
|
||||||
if(adapter->rx_ps) {
|
if (adapter->rx_ps_pages) {
|
||||||
/* Configure extra packet-split registers */
|
/* Configure extra packet-split registers */
|
||||||
rfctl = E1000_READ_REG(&adapter->hw, RFCTL);
|
rfctl = E1000_READ_REG(&adapter->hw, RFCTL);
|
||||||
rfctl |= E1000_RFCTL_EXTEN;
|
rfctl |= E1000_RFCTL_EXTEN;
|
||||||
|
@ -1559,12 +1566,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
|
||||||
|
|
||||||
psrctl |= adapter->rx_ps_bsize0 >>
|
psrctl |= adapter->rx_ps_bsize0 >>
|
||||||
E1000_PSRCTL_BSIZE0_SHIFT;
|
E1000_PSRCTL_BSIZE0_SHIFT;
|
||||||
psrctl |= PAGE_SIZE >>
|
|
||||||
E1000_PSRCTL_BSIZE1_SHIFT;
|
switch (adapter->rx_ps_pages) {
|
||||||
psrctl |= PAGE_SIZE <<
|
case 3:
|
||||||
E1000_PSRCTL_BSIZE2_SHIFT;
|
psrctl |= PAGE_SIZE <<
|
||||||
psrctl |= PAGE_SIZE <<
|
E1000_PSRCTL_BSIZE3_SHIFT;
|
||||||
E1000_PSRCTL_BSIZE3_SHIFT;
|
case 2:
|
||||||
|
psrctl |= PAGE_SIZE <<
|
||||||
|
E1000_PSRCTL_BSIZE2_SHIFT;
|
||||||
|
case 1:
|
||||||
|
psrctl |= PAGE_SIZE >>
|
||||||
|
E1000_PSRCTL_BSIZE1_SHIFT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl);
|
E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl);
|
||||||
}
|
}
|
||||||
|
@ -1590,7 +1604,7 @@ e1000_configure_rx(struct e1000_adapter *adapter)
|
||||||
int i;
|
int i;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(adapter->rx_ps) {
|
if (adapter->rx_ps_pages) {
|
||||||
rdlen = adapter->rx_ring[0].count *
|
rdlen = adapter->rx_ring[0].count *
|
||||||
sizeof(union e1000_rx_desc_packet_split);
|
sizeof(union e1000_rx_desc_packet_split);
|
||||||
adapter->clean_rx = e1000_clean_rx_irq_ps;
|
adapter->clean_rx = e1000_clean_rx_irq_ps;
|
||||||
|
@ -1700,8 +1714,8 @@ e1000_configure_rx(struct e1000_adapter *adapter)
|
||||||
|
|
||||||
/* Enable 82571 IPv4 payload checksum for UDP fragments
|
/* Enable 82571 IPv4 payload checksum for UDP fragments
|
||||||
* Must be used in conjunction with packet-split. */
|
* Must be used in conjunction with packet-split. */
|
||||||
if((adapter->hw.mac_type > e1000_82547_rev_2) &&
|
if ((hw->mac_type >= e1000_82571) &&
|
||||||
(adapter->rx_ps)) {
|
(adapter->rx_ps_pages)) {
|
||||||
rxcsum |= E1000_RXCSUM_IPPCSE;
|
rxcsum |= E1000_RXCSUM_IPPCSE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1906,7 +1920,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter,
|
||||||
dev_kfree_skb(buffer_info->skb);
|
dev_kfree_skb(buffer_info->skb);
|
||||||
buffer_info->skb = NULL;
|
buffer_info->skb = NULL;
|
||||||
|
|
||||||
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
|
for(j = 0; j < adapter->rx_ps_pages; j++) {
|
||||||
if(!ps_page->ps_page[j]) break;
|
if(!ps_page->ps_page[j]) break;
|
||||||
pci_unmap_single(pdev,
|
pci_unmap_single(pdev,
|
||||||
ps_page_dma->ps_page_dma[j],
|
ps_page_dma->ps_page_dma[j],
|
||||||
|
@ -3551,7 +3565,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
|
||||||
/* Good Receive */
|
/* Good Receive */
|
||||||
skb_put(skb, length);
|
skb_put(skb, length);
|
||||||
|
|
||||||
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
|
for(j = 0; j < adapter->rx_ps_pages; j++) {
|
||||||
if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j])))
|
if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j])))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3572,11 +3586,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
|
||||||
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
|
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
|
||||||
skb->protocol = eth_type_trans(skb, netdev);
|
skb->protocol = eth_type_trans(skb, netdev);
|
||||||
|
|
||||||
#ifdef HAVE_RX_ZERO_COPY
|
|
||||||
if(likely(rx_desc->wb.upper.header_status &
|
if(likely(rx_desc->wb.upper.header_status &
|
||||||
E1000_RXDPS_HDRSTAT_HDRSP))
|
E1000_RXDPS_HDRSTAT_HDRSP)) {
|
||||||
|
adapter->rx_hdr_split++;
|
||||||
|
#ifdef HAVE_RX_ZERO_COPY
|
||||||
skb_shinfo(skb)->zero_copy = TRUE;
|
skb_shinfo(skb)->zero_copy = TRUE;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#ifdef CONFIG_E1000_NAPI
|
#ifdef CONFIG_E1000_NAPI
|
||||||
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
|
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
|
||||||
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
|
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
|
||||||
|
@ -3740,22 +3756,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
|
||||||
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
|
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
|
||||||
|
|
||||||
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
|
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
|
||||||
if(unlikely(!ps_page->ps_page[j])) {
|
if (j < adapter->rx_ps_pages) {
|
||||||
ps_page->ps_page[j] =
|
if (likely(!ps_page->ps_page[j])) {
|
||||||
alloc_page(GFP_ATOMIC);
|
ps_page->ps_page[j] =
|
||||||
if(unlikely(!ps_page->ps_page[j]))
|
alloc_page(GFP_ATOMIC);
|
||||||
goto no_buffers;
|
if (unlikely(!ps_page->ps_page[j]))
|
||||||
ps_page_dma->ps_page_dma[j] =
|
goto no_buffers;
|
||||||
pci_map_page(pdev,
|
ps_page_dma->ps_page_dma[j] =
|
||||||
ps_page->ps_page[j],
|
pci_map_page(pdev,
|
||||||
0, PAGE_SIZE,
|
ps_page->ps_page[j],
|
||||||
PCI_DMA_FROMDEVICE);
|
0, PAGE_SIZE,
|
||||||
}
|
PCI_DMA_FROMDEVICE);
|
||||||
/* Refresh the desc even if buffer_addrs didn't
|
}
|
||||||
* change because each write-back erases this info.
|
/* Refresh the desc even if buffer_addrs didn't
|
||||||
*/
|
* change because each write-back erases
|
||||||
rx_desc->read.buffer_addr[j+1] =
|
* this info.
|
||||||
cpu_to_le64(ps_page_dma->ps_page_dma[j]);
|
*/
|
||||||
|
rx_desc->read.buffer_addr[j+1] =
|
||||||
|
cpu_to_le64(ps_page_dma->ps_page_dma[j]);
|
||||||
|
} else
|
||||||
|
rx_desc->read.buffer_addr[j+1] = ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
|
skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
|
||||||
|
|
Reference in a new issue