summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/e1000e/netdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel/e1000e/netdev.c')
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c90
1 files changed, 84 insertions, 6 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 263bf5f02eb1..b196d79e108d 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -845,6 +845,13 @@ check_page:
}
}
+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
* @adapter: board private structure
@@ -964,6 +971,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
e1000_rx_checksum(adapter, staterr,
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,
rx_desc->wb.upper.vlan);
@@ -1325,6 +1334,8 @@ copydone:
e1000_rx_checksum(adapter, staterr,
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 &
cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
adapter->rx_hdr_split++;
@@ -1497,6 +1508,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
e1000_rx_checksum(adapter, staterr,
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 */
total_rx_bytes += skb->len;
total_rx_packets++;
@@ -3271,6 +3284,42 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
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
* @adapter: private board structure
@@ -3283,6 +3332,9 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_init_manageability_pt(adapter);
e1000_configure_tx(adapter);
+
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ e1000e_setup_rss_hash(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
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)
int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
/* Jumbo frame support */
- if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
- !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
- e_err("Jumbo Frames not supported.\n");
- return -EINVAL;
+ if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
+ if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+ e_err("Jumbo Frames not supported.\n");
+ 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 */
@@ -5934,7 +5998,7 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
}
static int e1000_set_features(struct net_device *netdev,
- netdev_features_t features)
+ netdev_features_t features)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features;
@@ -5943,9 +6007,22 @@ static int e1000_set_features(struct net_device *netdev,
adapter->flags |= FLAG_TSO_FORCE;
if (!(changed & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX |
- NETIF_F_RXCSUM)))
+ NETIF_F_RXCSUM | NETIF_F_RXHASH)))
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))
e1000e_reinit_locked(adapter);
else
@@ -6136,6 +6213,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_TSO |
NETIF_F_TSO6 |
+ NETIF_F_RXHASH |
NETIF_F_RXCSUM |
NETIF_F_HW_CSUM);