Commit 70495a50 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher

e1000e: add Receive Packet Steering (RPS) support

Enable RPS by default.  Disallow jumbo frames when both receive checksum
and receive hashing are enabled because the hardware cannot do both IP
payload checksum (enabled when receive checksum is enabled when using
packet split which is used for jumbo frames) and provide RSS hash at the
same time.

v2: added ethtool command to query flow hashing behavior per Ben Hutchings
    and changed the type of rsskey to cleanup the setting of the register
    array and avoid unnecessary casts (as pointed out by Joe Perches).
    The long error messages are not changed since there is nothing in
    the kernel ./Documentation that suggests the preferred method for
    dealing with long messages other than to never break strings; leaving
    them as-is for now.
Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent afd12939
...@@ -126,6 +126,13 @@ ...@@ -126,6 +126,13 @@
E1000_RXDEXT_STATERR_CXE | \ E1000_RXDEXT_STATERR_CXE | \
E1000_RXDEXT_STATERR_RXE) E1000_RXDEXT_STATERR_RXE)
#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 #define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
/* Management Control */ /* Management Control */
...@@ -326,6 +333,7 @@ ...@@ -326,6 +333,7 @@
/* Receive Checksum Control */ /* Receive Checksum Control */
#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ #define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
/* Header split receive */ /* Header split receive */
#define E1000_RFCTL_NFSW_DIS 0x00000040 #define E1000_RFCTL_NFSW_DIS 0x00000040
......
...@@ -1955,6 +1955,53 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, ...@@ -1955,6 +1955,53 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
} }
} }
static int e1000_get_rxnfc(struct net_device *netdev,
struct ethtool_rxnfc *info, u32 *rule_locs)
{
info->data = 0;
switch (info->cmd) {
case ETHTOOL_GRXFH: {
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 mrqc = er32(MRQC);
if (!(mrqc & E1000_MRQC_RSS_FIELD_MASK))
return 0;
switch (info->flow_type) {
case TCP_V4_FLOW:
if (mrqc & E1000_MRQC_RSS_FIELD_IPV4_TCP)
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case IPV4_FLOW:
if (mrqc & E1000_MRQC_RSS_FIELD_IPV4)
info->data |= RXH_IP_SRC | RXH_IP_DST;
break;
case TCP_V6_FLOW:
if (mrqc & E1000_MRQC_RSS_FIELD_IPV6_TCP)
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case IPV6_FLOW:
if (mrqc & E1000_MRQC_RSS_FIELD_IPV6)
info->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
break;
}
return 0;
}
default:
return -EOPNOTSUPP;
}
}
static const struct ethtool_ops e1000_ethtool_ops = { static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings, .get_settings = e1000_get_settings,
.set_settings = e1000_set_settings, .set_settings = e1000_set_settings,
...@@ -1981,6 +2028,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { ...@@ -1981,6 +2028,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_sset_count = e1000e_get_sset_count, .get_sset_count = e1000e_get_sset_count,
.get_coalesce = e1000_get_coalesce, .get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce, .set_coalesce = e1000_set_coalesce,
.get_rxnfc = e1000_get_rxnfc,
}; };
void e1000e_set_ethtool_ops(struct net_device *netdev) void e1000e_set_ethtool_ops(struct net_device *netdev)
......
...@@ -204,6 +204,7 @@ enum e1e_registers { ...@@ -204,6 +204,7 @@ enum e1e_registers {
E1000_WUC = 0x05800, /* Wakeup Control - RW */ E1000_WUC = 0x05800, /* Wakeup Control - RW */
E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */
E1000_WUS = 0x05810, /* Wakeup Status - RO */ E1000_WUS = 0x05810, /* Wakeup Status - RO */
E1000_MRQC = 0x05818, /* Multiple Receive Control - RW */
E1000_MANC = 0x05820, /* Management Control - RW */ E1000_MANC = 0x05820, /* Management Control - RW */
E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */ E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */
E1000_HOST_IF = 0x08800, /* Host Interface */ E1000_HOST_IF = 0x08800, /* Host Interface */
...@@ -219,6 +220,10 @@ enum e1e_registers { ...@@ -219,6 +220,10 @@ enum e1e_registers {
E1000_SWSM = 0x05B50, /* SW Semaphore */ E1000_SWSM = 0x05B50, /* SW Semaphore */
E1000_FWSM = 0x05B54, /* FW Semaphore */ E1000_FWSM = 0x05B54, /* FW Semaphore */
E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */
E1000_RETA_BASE = 0x05C00, /* Redirection Table - RW */
#define E1000_RETA(_n) (E1000_RETA_BASE + ((_n) * 4))
E1000_RSSRK_BASE = 0x05C80, /* RSS Random Key - RW */
#define E1000_RSSRK(_n) (E1000_RSSRK_BASE + ((_n) * 4))
E1000_FFLT_DBG = 0x05F04, /* Debug Register */ E1000_FFLT_DBG = 0x05F04, /* Debug Register */
E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */ E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
#define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4)) #define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4))
......
...@@ -845,6 +845,13 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, ...@@ -845,6 +845,13 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
} }
} }
static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss,
struct sk_buff *skb)
{
if (netdev->features & NETIF_F_RXHASH)
skb->rxhash = le32_to_cpu(rss);
}
/** /**
* e1000_clean_rx_irq - Send received data up the network stack; legacy * e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure * @adapter: board private structure
...@@ -964,6 +971,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, ...@@ -964,6 +971,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
e1000_rx_checksum(adapter, staterr, e1000_rx_checksum(adapter, staterr,
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
e1000_receive_skb(adapter, netdev, skb, staterr, e1000_receive_skb(adapter, netdev, skb, staterr,
rx_desc->wb.upper.vlan); rx_desc->wb.upper.vlan);
...@@ -1325,6 +1334,8 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, ...@@ -1325,6 +1334,8 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
e1000_rx_checksum(adapter, staterr, e1000_rx_checksum(adapter, staterr,
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
if (rx_desc->wb.upper.header_status & if (rx_desc->wb.upper.header_status &
cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)) cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
adapter->rx_hdr_split++; adapter->rx_hdr_split++;
...@@ -1497,6 +1508,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, ...@@ -1497,6 +1508,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
e1000_rx_checksum(adapter, staterr, e1000_rx_checksum(adapter, staterr,
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
/* probably a little skewed due to removing CRC */ /* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len; total_rx_bytes += skb->len;
total_rx_packets++; total_rx_packets++;
...@@ -3271,6 +3284,42 @@ static void e1000e_set_rx_mode(struct net_device *netdev) ...@@ -3271,6 +3284,42 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
e1000e_vlan_strip_disable(adapter); e1000e_vlan_strip_disable(adapter);
} }
static void e1000e_setup_rss_hash(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
int i;
static const u32 rsskey[10] = {
0xda565a6d, 0xc20e5b25, 0x3d256741, 0xb08fa343, 0xcb2bcad0,
0xb4307bae, 0xa32dcb77, 0x0cf23080, 0x3bb7426a, 0xfa01acbe
};
/* Fill out hash function seed */
for (i = 0; i < 10; i++)
ew32(RSSRK(i), rsskey[i]);
/* Direct all traffic to queue 0 */
for (i = 0; i < 32; i++)
ew32(RETA(i), 0);
/*
* Disable raw packet checksumming so that RSS hash is placed in
* descriptor on writeback.
*/
rxcsum = er32(RXCSUM);
rxcsum |= E1000_RXCSUM_PCSD;
ew32(RXCSUM, rxcsum);
mrqc = (E1000_MRQC_RSS_FIELD_IPV4 |
E1000_MRQC_RSS_FIELD_IPV4_TCP |
E1000_MRQC_RSS_FIELD_IPV6 |
E1000_MRQC_RSS_FIELD_IPV6_TCP |
E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
ew32(MRQC, mrqc);
}
/** /**
* e1000_configure - configure the hardware for Rx and Tx * e1000_configure - configure the hardware for Rx and Tx
* @adapter: private board structure * @adapter: private board structure
...@@ -3283,6 +3332,9 @@ static void e1000_configure(struct e1000_adapter *adapter) ...@@ -3283,6 +3332,9 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_init_manageability_pt(adapter); e1000_init_manageability_pt(adapter);
e1000_configure_tx(adapter); e1000_configure_tx(adapter);
if (adapter->netdev->features & NETIF_F_RXHASH)
e1000e_setup_rss_hash(adapter);
e1000_setup_rctl(adapter); e1000_setup_rctl(adapter);
e1000_configure_rx(adapter); e1000_configure_rx(adapter);
adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring), adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring),
...@@ -5168,10 +5220,22 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -5168,10 +5220,22 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
/* Jumbo frame support */ /* Jumbo frame support */
if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) && if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
e_err("Jumbo Frames not supported.\n"); e_err("Jumbo Frames not supported.\n");
return -EINVAL; return -EINVAL;
}
/*
* IP payload checksum (enabled with jumbos/packet-split when
* Rx checksum is enabled) and generation of RSS hash is
* mutually exclusive in the hardware.
*/
if ((netdev->features & NETIF_F_RXCSUM) &&
(netdev->features & NETIF_F_RXHASH)) {
e_err("Jumbo frames cannot be enabled when both receive checksum offload and receive hashing are enabled. Disable one of the receive offload features before enabling jumbos.\n");
return -EINVAL;
}
} }
/* Supported frame sizes */ /* Supported frame sizes */
...@@ -5934,7 +5998,7 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) ...@@ -5934,7 +5998,7 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
} }
static int e1000_set_features(struct net_device *netdev, static int e1000_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_adapter *adapter = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features; netdev_features_t changed = features ^ netdev->features;
...@@ -5943,9 +6007,22 @@ static int e1000_set_features(struct net_device *netdev, ...@@ -5943,9 +6007,22 @@ static int e1000_set_features(struct net_device *netdev,
adapter->flags |= FLAG_TSO_FORCE; adapter->flags |= FLAG_TSO_FORCE;
if (!(changed & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | if (!(changed & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX |
NETIF_F_RXCSUM))) NETIF_F_RXCSUM | NETIF_F_RXHASH)))
return 0; return 0;
/*
* IP payload checksum (enabled with jumbos/packet-split when Rx
* checksum is enabled) and generation of RSS hash is mutually
* exclusive in the hardware.
*/
if (adapter->rx_ps_pages &&
(features & NETIF_F_RXCSUM) && (features & NETIF_F_RXHASH)) {
e_err("Enabling both receive checksum offload and receive hashing is not possible with jumbo frames. Disable jumbos or enable only one of the receive offload features.\n");
return -EINVAL;
}
netdev->features = features;
if (netif_running(netdev)) if (netif_running(netdev))
e1000e_reinit_locked(adapter); e1000e_reinit_locked(adapter);
else else
...@@ -6136,6 +6213,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, ...@@ -6136,6 +6213,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_TX |
NETIF_F_TSO | NETIF_F_TSO |
NETIF_F_TSO6 | NETIF_F_TSO6 |
NETIF_F_RXHASH |
NETIF_F_RXCSUM | NETIF_F_RXCSUM |
NETIF_F_HW_CSUM); NETIF_F_HW_CSUM);
......
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