|
@@ -2328,6 +2328,48 @@ static int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int ixgbe_get_rss_hash_opts(struct ixgbe_adapter *adapter,
|
|
|
+ struct ethtool_rxnfc *cmd)
|
|
|
+{
|
|
|
+ cmd->data = 0;
|
|
|
+
|
|
|
+ /* if RSS is disabled then report no hashing */
|
|
|
+ if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Report default options for RSS on ixgbe */
|
|
|
+ switch (cmd->flow_type) {
|
|
|
+ case TCP_V4_FLOW:
|
|
|
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
+ case UDP_V4_FLOW:
|
|
|
+ if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
|
|
|
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
+ case SCTP_V4_FLOW:
|
|
|
+ case AH_ESP_V4_FLOW:
|
|
|
+ case AH_V4_FLOW:
|
|
|
+ case ESP_V4_FLOW:
|
|
|
+ case IPV4_FLOW:
|
|
|
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
|
|
+ break;
|
|
|
+ case TCP_V6_FLOW:
|
|
|
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
+ case UDP_V6_FLOW:
|
|
|
+ if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
|
|
|
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
+ case SCTP_V6_FLOW:
|
|
|
+ case AH_ESP_V6_FLOW:
|
|
|
+ case AH_V6_FLOW:
|
|
|
+ case ESP_V6_FLOW:
|
|
|
+ case IPV6_FLOW:
|
|
|
+ cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
|
|
u32 *rule_locs)
|
|
|
{
|
|
@@ -2349,6 +2391,9 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
|
|
case ETHTOOL_GRXCLSRLALL:
|
|
|
ret = ixgbe_get_ethtool_fdir_all(adapter, cmd, rule_locs);
|
|
|
break;
|
|
|
+ case ETHTOOL_GRXFH:
|
|
|
+ ret = ixgbe_get_rss_hash_opts(adapter, cmd);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -2583,6 +2628,111 @@ static int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+#define UDP_RSS_FLAGS (IXGBE_FLAG2_RSS_FIELD_IPV4_UDP | \
|
|
|
+ IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
|
|
|
+static int ixgbe_set_rss_hash_opt(struct ixgbe_adapter *adapter,
|
|
|
+ struct ethtool_rxnfc *nfc)
|
|
|
+{
|
|
|
+ u32 flags2 = adapter->flags2;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * RSS does not support anything other than hashing
|
|
|
+ * to queues on src and dst IPs and ports
|
|
|
+ */
|
|
|
+ if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
|
|
|
+ RXH_L4_B_0_1 | RXH_L4_B_2_3))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ switch (nfc->flow_type) {
|
|
|
+ case TCP_V4_FLOW:
|
|
|
+ case TCP_V6_FLOW:
|
|
|
+ if (!(nfc->data & RXH_IP_SRC) ||
|
|
|
+ !(nfc->data & RXH_IP_DST) ||
|
|
|
+ !(nfc->data & RXH_L4_B_0_1) ||
|
|
|
+ !(nfc->data & RXH_L4_B_2_3))
|
|
|
+ return -EINVAL;
|
|
|
+ break;
|
|
|
+ case UDP_V4_FLOW:
|
|
|
+ if (!(nfc->data & RXH_IP_SRC) ||
|
|
|
+ !(nfc->data & RXH_IP_DST))
|
|
|
+ return -EINVAL;
|
|
|
+ switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
|
|
+ case 0:
|
|
|
+ flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
|
|
|
+ break;
|
|
|
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
|
|
+ flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case UDP_V6_FLOW:
|
|
|
+ if (!(nfc->data & RXH_IP_SRC) ||
|
|
|
+ !(nfc->data & RXH_IP_DST))
|
|
|
+ return -EINVAL;
|
|
|
+ switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
|
|
+ case 0:
|
|
|
+ flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
|
|
|
+ break;
|
|
|
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
|
|
+ flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case AH_ESP_V4_FLOW:
|
|
|
+ case AH_V4_FLOW:
|
|
|
+ case ESP_V4_FLOW:
|
|
|
+ case SCTP_V4_FLOW:
|
|
|
+ case AH_ESP_V6_FLOW:
|
|
|
+ case AH_V6_FLOW:
|
|
|
+ case ESP_V6_FLOW:
|
|
|
+ case SCTP_V6_FLOW:
|
|
|
+ if (!(nfc->data & RXH_IP_SRC) ||
|
|
|
+ !(nfc->data & RXH_IP_DST) ||
|
|
|
+ (nfc->data & RXH_L4_B_0_1) ||
|
|
|
+ (nfc->data & RXH_L4_B_2_3))
|
|
|
+ return -EINVAL;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if we changed something we need to update flags */
|
|
|
+ if (flags2 != adapter->flags2) {
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ u32 mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
|
|
|
+
|
|
|
+ if ((flags2 & UDP_RSS_FLAGS) &&
|
|
|
+ !(adapter->flags2 & UDP_RSS_FLAGS))
|
|
|
+ e_warn(drv, "enabling UDP RSS: fragmented packets"
|
|
|
+ " may arrive out of order to the stack above\n");
|
|
|
+
|
|
|
+ adapter->flags2 = flags2;
|
|
|
+
|
|
|
+ /* Perform hash on these packet types */
|
|
|
+ mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
|
|
|
+ | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
|
|
|
+ | IXGBE_MRQC_RSS_FIELD_IPV6
|
|
|
+ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
|
|
|
+
|
|
|
+ mrqc &= ~(IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
|
|
|
+ IXGBE_MRQC_RSS_FIELD_IPV6_UDP);
|
|
|
+
|
|
|
+ if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
|
|
|
+ mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
|
|
|
+
|
|
|
+ if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
|
|
|
+ mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
|
|
|
+
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
|
|
{
|
|
|
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
|
@@ -2595,6 +2745,9 @@ static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
|
|
case ETHTOOL_SRXCLSRLDEL:
|
|
|
ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd);
|
|
|
break;
|
|
|
+ case ETHTOOL_SRXFH:
|
|
|
+ ret = ixgbe_set_rss_hash_opt(adapter, cmd);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|