Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a713e7c authored by Peter Waskiewicz's avatar Peter Waskiewicz Committed by David S. Miller
Browse files

ixgbe: Add support for the new ethtool n-tuple programming interface



This patch adds n-tuple filter programming to 82599.

Signed-off-by: default avatarPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15682bc4
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -453,6 +453,10 @@ extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc);
extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
                                                 struct ixgbe_atr_input *input,
                                                 u8 queue);
extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
                                      struct ixgbe_atr_input *input,
                                      struct ixgbe_atr_input_masks *input_masks,
                                      u16 soft_id, u8 queue);
extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input,
                                       u16 vlan_id);
extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input,
+93 −13
Original line number Diff line number Diff line
@@ -1439,6 +1439,9 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
	/* Send interrupt when 64 filters are left */
	fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT;

	/* Initialize the drop queue to Rx queue 127 */
	fdirctrl |= (127 << IXGBE_FDIRCTRL_DROP_Q_SHIFT);

	switch (pballoc) {
	case IXGBE_FDIR_PBALLOC_64K:
		/* 2k - 1 perfect filters */
@@ -1628,6 +1631,7 @@ static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input,
 *  ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream
 *  @input: input stream to modify
 *  @vlan: the VLAN id to load
 *  @vlan_mask: bitwise mask for the VLAN
 **/
s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan)
{
@@ -1641,6 +1645,7 @@ s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan)
 *  ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address
 *  @input: input stream to modify
 *  @src_addr: the IP address to load
 *  @src_addr_mask: bitwise mask for the source IP address
 **/
s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr)
{
@@ -1658,6 +1663,7 @@ s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr)
 *  ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address
 *  @input: input stream to modify
 *  @dst_addr: the IP address to load
 *  @dst_addr_mask: bitwise mask for the destination IP address
 **/
s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
{
@@ -1761,6 +1767,7 @@ s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input,
 *  ixgbe_atr_set_src_port_82599 - Sets the source port
 *  @input: input stream to modify
 *  @src_port: the source port to load
 *  @src_port_mask: bitwise mask for the source port
 **/
s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port)
{
@@ -1774,6 +1781,7 @@ s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port)
 *  ixgbe_atr_set_dst_port_82599 - Sets the destination port
 *  @input: input stream to modify
 *  @dst_port: the destination port to load
 *  @dst_port_mask: bitwise mask for the destination port
 **/
s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port)
{
@@ -1826,8 +1834,7 @@ s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type)
 *  @input: input stream to search
 *  @vlan: the VLAN id to load
 **/
static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input,
                                       u16 *vlan)
static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan)
{
	*vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET];
	*vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8;
@@ -2083,6 +2090,8 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
 *  ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
 *  @hw: pointer to hardware structure
 *  @input: input bitstream
 *  @input_masks: bitwise masks for relevant fields
 *  @soft_id: software index into the silicon hash tables for filter storage
 *  @queue: queue index to direct traffic to
 *
 *  Note that the caller to this function must lock before calling, since the
@@ -2090,16 +2099,17 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
 **/
s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
                                      struct ixgbe_atr_input *input,
                                               u16 soft_id,
                                               u8 queue)
                                      struct ixgbe_atr_input_masks *input_masks,
                                      u16 soft_id, u8 queue)
{
	u32 fdircmd = 0;
	u32 fdirhash;
	u32 src_ipv4, dst_ipv4;
	u32 src_ipv4 = 0, dst_ipv4 = 0;
	u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4;
	u16 src_port, dst_port, vlan_id, flex_bytes;
	u16 bucket_hash;
	u8  l4type;
	u8  fdirm = 0;

	/* Get our input values */
	ixgbe_atr_get_l4type_82599(input, &l4type);
@@ -2154,7 +2164,6 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
		/* IPv4 */
		ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4);
		IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4);

	}

	ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4);
@@ -2165,6 +2174,77 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
	IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port |
	              (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));

	/*
	 * Program the relevant mask registers.  If src/dst_port or src/dst_addr
	 * are zero, then assume a full mask for that field.  Also assume that
	 * a VLAN of 0 is unspecified, so mask that out as well.  L4type
	 * cannot be masked out in this implementation.
	 *
	 * This also assumes IPv4 only.  IPv6 masking isn't supported at this
	 * point in time.
	 */
	if (src_ipv4 == 0)
		IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, 0xffffffff);
	else
		IXGBE_WRITE_REG(hw, IXGBE_FDIRSIP4M, input_masks->src_ip_mask);

	if (dst_ipv4 == 0)
		IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, 0xffffffff);
	else
		IXGBE_WRITE_REG(hw, IXGBE_FDIRDIP4M, input_masks->dst_ip_mask);

	switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
	case IXGBE_ATR_L4TYPE_TCP:
		if (src_port == 0)
			IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, 0xffff);
		else
			IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
			                input_masks->src_port_mask);

		if (dst_port == 0)
			IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
			               (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
			                (0xffff << 16)));
		else
			IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM,
			               (IXGBE_READ_REG(hw, IXGBE_FDIRTCPM) |
			                (input_masks->dst_port_mask << 16)));
		break;
	case IXGBE_ATR_L4TYPE_UDP:
		if (src_port == 0)
			IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, 0xffff);
		else
			IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
			                input_masks->src_port_mask);

		if (dst_port == 0)
			IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
			               (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
			                (0xffff << 16)));
		else
			IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM,
			               (IXGBE_READ_REG(hw, IXGBE_FDIRUDPM) |
			                (input_masks->src_port_mask << 16)));
		break;
	default:
		/* this already would have failed above */
		break;
	}

	/* Program the last mask register, FDIRM */
	if (input_masks->vlan_id_mask || !vlan_id)
		/* Mask both VLAN and VLANP - bits 0 and 1 */
		fdirm |= 0x3;

	if (input_masks->data_mask || !flex_bytes)
		/* Flex bytes need masking, so mask the whole thing - bit 4 */
		fdirm |= 0x10;

	/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
	fdirm |= 0x24;

	IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);

	fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW;
	fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE;
	fdircmd |= IXGBE_FDIRCMD_LAST;
+108 −3
Original line number Diff line number Diff line
@@ -979,6 +979,9 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
		return IXGBE_TEST_LEN;
	case ETH_SS_STATS:
		return IXGBE_STATS_LEN;
	case ETH_SS_NTUPLE_FILTERS:
		return (ETHTOOL_MAX_NTUPLE_LIST_ENTRY *
		        ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY);
	default:
		return -EOPNOTSUPP;
	}
@@ -2150,23 +2153,124 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
static int ixgbe_set_flags(struct net_device *netdev, u32 data)
{
	struct ixgbe_adapter *adapter = netdev_priv(netdev);
	bool need_reset = false;

	ethtool_op_set_flags(netdev, data);

	if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
		return 0;

	/* if state changes we need to update adapter->flags and reset */
	if ((!!(data & ETH_FLAG_LRO)) != 
	    (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
		adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
		need_reset = true;
	}

	/*
	 * Check if Flow Director n-tuple support was enabled or disabled.  If
	 * the state changed, we need to reset.
	 */
	if ((adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) &&
	    (!(data & ETH_FLAG_NTUPLE))) {
		/* turn off Flow Director perfect, set hash and reset */
		adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
		adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
		need_reset = true;
	} else if ((!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) &&
	           (data & ETH_FLAG_NTUPLE)) {
		/* turn off Flow Director hash, enable perfect and reset */
		adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
		adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
		need_reset = true;
	} else {
		/* no state change */
	}

	if (need_reset) {
		if (netif_running(netdev))
			ixgbe_reinit_locked(adapter);
		else
			ixgbe_reset(adapter);
	}

	return 0;
}

static int ixgbe_set_rx_ntuple(struct net_device *dev,
                               struct ethtool_rx_ntuple *cmd)
{
	struct ixgbe_adapter *adapter = netdev_priv(dev);
	struct ethtool_rx_ntuple_flow_spec fs = cmd->fs;
	struct ixgbe_atr_input input_struct;
	struct ixgbe_atr_input_masks input_masks;
	int target_queue;

	if (adapter->hw.mac.type == ixgbe_mac_82598EB)
		return -EOPNOTSUPP;

	/*
	 * Don't allow programming if the action is a queue greater than
	 * the number of online Tx queues.
	 */
	if ((fs.action >= adapter->num_tx_queues) ||
	    (fs.action < ETHTOOL_RXNTUPLE_ACTION_DROP))
		return -EINVAL;

	memset(&input_struct, 0, sizeof(struct ixgbe_atr_input));
	memset(&input_masks, 0, sizeof(struct ixgbe_atr_input_masks));

	input_masks.src_ip_mask = fs.m_u.tcp_ip4_spec.ip4src;
	input_masks.dst_ip_mask = fs.m_u.tcp_ip4_spec.ip4dst;
	input_masks.src_port_mask = fs.m_u.tcp_ip4_spec.psrc;
	input_masks.dst_port_mask = fs.m_u.tcp_ip4_spec.pdst;
	input_masks.vlan_id_mask = fs.vlan_tag_mask;
	/* only use the lowest 2 bytes for flex bytes */
	input_masks.data_mask = (fs.data_mask & 0xffff);

	switch (fs.flow_type) {
	case TCP_V4_FLOW:
		ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_TCP);
		break;
	case UDP_V4_FLOW:
		ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_UDP);
		break;
	case SCTP_V4_FLOW:
		ixgbe_atr_set_l4type_82599(&input_struct, IXGBE_ATR_L4TYPE_SCTP);
		break;
	default:
		return -1;
	}

	/* Mask bits from the inputs based on user-supplied mask */
	ixgbe_atr_set_src_ipv4_82599(&input_struct,
	            (fs.h_u.tcp_ip4_spec.ip4src & ~fs.m_u.tcp_ip4_spec.ip4src));
	ixgbe_atr_set_dst_ipv4_82599(&input_struct,
	            (fs.h_u.tcp_ip4_spec.ip4dst & ~fs.m_u.tcp_ip4_spec.ip4dst));
	/* 82599 expects these to be byte-swapped for perfect filtering */
	ixgbe_atr_set_src_port_82599(&input_struct,
	       ((ntohs(fs.h_u.tcp_ip4_spec.psrc)) & ~fs.m_u.tcp_ip4_spec.psrc));
	ixgbe_atr_set_dst_port_82599(&input_struct,
	       ((ntohs(fs.h_u.tcp_ip4_spec.pdst)) & ~fs.m_u.tcp_ip4_spec.pdst));

	/* VLAN and Flex bytes are either completely masked or not */
	if (!fs.vlan_tag_mask)
		ixgbe_atr_set_vlan_id_82599(&input_struct, fs.vlan_tag);

	if (!input_masks.data_mask)
		/* make sure we only use the first 2 bytes of user data */
		ixgbe_atr_set_flex_byte_82599(&input_struct,
		                              (fs.data & 0xffff));

	/* determine if we need to drop or route the packet */
	if (fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
		target_queue = MAX_RX_QUEUES - 1;
	else
		target_queue = fs.action;

	spin_lock(&adapter->fdir_perfect_lock);
	ixgbe_fdir_add_perfect_filter_82599(&adapter->hw, &input_struct,
	                                    &input_masks, 0, target_queue);
	spin_unlock(&adapter->fdir_perfect_lock);

	return 0;
}

static const struct ethtool_ops ixgbe_ethtool_ops = {
@@ -2204,6 +2308,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
	.set_coalesce           = ixgbe_set_coalesce,
	.get_flags              = ethtool_op_get_flags,
	.set_flags              = ixgbe_set_flags,
	.set_rx_ntuple          = ixgbe_set_rx_ntuple,
};

void ixgbe_set_ethtool_ops(struct net_device *netdev)
+14 −2
Original line number Diff line number Diff line
@@ -3253,6 +3253,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)

	netif_carrier_off(netdev);

	/* clear n-tuple filters that are cached */
	ethtool_ntuple_flush(netdev);

	if (!pci_channel_offline(adapter->pdev))
		ixgbe_reset(adapter);
	ixgbe_clean_all_tx_rings(adapter);
@@ -4187,6 +4190,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
{
	struct ixgbe_hw *hw = &adapter->hw;
	struct pci_dev *pdev = adapter->pdev;
	struct net_device *dev = adapter->netdev;
	unsigned int rss;
#ifdef CONFIG_IXGBE_DCB
	int j;
@@ -4214,10 +4218,18 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
		adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
		adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
		adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
		if (dev->features & NETIF_F_NTUPLE) {
			/* Flow Director perfect filter enabled */
			adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
			adapter->atr_sample_rate = 0;
			spin_lock_init(&adapter->fdir_perfect_lock);
		} else {
			/* Flow Director hash filters enabled */
			adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
			adapter->atr_sample_rate = 20;
		}
		adapter->ring_feature[RING_F_FDIR].indices =
		                                         IXGBE_MAX_FDIR_INDICES;
		adapter->atr_sample_rate = 20;
		adapter->fdir_pballoc = 0;
#ifdef IXGBE_FCOE
		adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
+9 −0
Original line number Diff line number Diff line
@@ -2129,6 +2129,15 @@ struct ixgbe_atr_input {
	u8 byte_stream[42];
};

struct ixgbe_atr_input_masks {
	u32 src_ip_mask;
	u32 dst_ip_mask;
	u16 src_port_mask;
	u16 dst_port_mask;
	u16 vlan_id_mask;
	u16 data_mask;
};

enum ixgbe_eeprom_type {
	ixgbe_eeprom_uninitialized = 0,
	ixgbe_eeprom_spi,