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

Commit 00e5ec4b authored by Mitch Williams's avatar Mitch Williams Committed by Jeff Kirsher
Browse files

i40evf: support packet split receive



Support packet split receive on VFs. This is off by default but can be
enabled using ethtool private flags. Because we need to trigger a reset
from outside of i40evf_main.c, create a new function to do so, and
export it.

Also update copyright year in file headers.

Change-ID: I721aa5d70113d3d6d94102e5f31526f6fc57cbbb
Signed-off-by: default avatarMitch Williams <mitch.a.williams@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent cb5c260e
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
/*******************************************************************************
 *
 * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
 * Copyright(c) 2013 - 2014 Intel Corporation.
 * Copyright(c) 2013 - 2016 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
@@ -274,6 +274,9 @@ struct i40evf_adapter {
};


/* Ethtool Private Flags */
#define I40EVF_PRIV_FLAGS_PS		BIT(0)

/* needed by i40evf_ethtool.c */
extern char i40evf_driver_name[];
extern const char i40evf_driver_version[];
@@ -281,6 +284,7 @@ extern const char i40evf_driver_version[];
int i40evf_up(struct i40evf_adapter *adapter);
void i40evf_down(struct i40evf_adapter *adapter);
int i40evf_process_config(struct i40evf_adapter *adapter);
void i40evf_schedule_reset(struct i40evf_adapter *adapter);
void i40evf_reset(struct i40evf_adapter *adapter);
void i40evf_set_ethtool_ops(struct net_device *netdev);
void i40evf_update_stats(struct i40evf_adapter *adapter);
+66 −1
Original line number Diff line number Diff line
/*******************************************************************************
 *
 * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
 * Copyright(c) 2013 - 2015 Intel Corporation.
 * Copyright(c) 2013 - 2016 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
@@ -63,6 +63,12 @@ static const struct i40evf_stats i40evf_gstrings_stats[] = {
#define I40EVF_STATS_LEN(_dev) \
	(I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))

static const char i40evf_priv_flags_strings[][ETH_GSTRING_LEN] = {
	"packet-split",
};

#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_priv_flags_strings)

/**
 * i40evf_get_settings - Get Link Speed and Duplex settings
 * @netdev: network interface device structure
@@ -97,6 +103,8 @@ static int i40evf_get_sset_count(struct net_device *netdev, int sset)
{
	if (sset == ETH_SS_STATS)
		return I40EVF_STATS_LEN(netdev);
	else if (sset == ETH_SS_PRIV_FLAGS)
		return I40EVF_PRIV_FLAGS_STR_LEN;
	else
		return -EINVAL;
}
@@ -162,6 +170,12 @@ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
			snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
			p += ETH_GSTRING_LEN;
		}
	} else if (sset == ETH_SS_PRIV_FLAGS) {
		for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
			memcpy(data, i40evf_priv_flags_strings[i],
			       ETH_GSTRING_LEN);
			data += ETH_GSTRING_LEN;
		}
	}
}

@@ -211,6 +225,7 @@ static void i40evf_get_drvinfo(struct net_device *netdev,
	strlcpy(drvinfo->version, i40evf_driver_version, 32);
	strlcpy(drvinfo->fw_version, "N/A", 4);
	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
	drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN;
}

/**
@@ -710,6 +725,54 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
				 I40EVF_HLUT_ARRAY_SIZE);
}

/**
 * i40evf_get_priv_flags - report device private flags
 * @dev: network interface device structure
 *
 * The get string set count and the string set should be matched for each
 * flag returned.  Add new strings for each flag to the i40e_priv_flags_strings
 * array.
 *
 * Returns a u32 bitmap of flags.
 **/
static u32 i40evf_get_priv_flags(struct net_device *dev)
{
	struct i40evf_adapter *adapter = netdev_priv(dev);
	u32 ret_flags = 0;

	ret_flags |= adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ?
		I40EVF_PRIV_FLAGS_PS : 0;

	return ret_flags;
}

/**
 * i40evf_set_priv_flags - set private flags
 * @dev: network interface device structure
 * @flags: bit flags to be set
 **/
static int i40evf_set_priv_flags(struct net_device *dev, u32 flags)
{
	struct i40evf_adapter *adapter = netdev_priv(dev);
	bool reset_required = false;

	if ((flags & I40EVF_PRIV_FLAGS_PS) &&
	    !(adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
		adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
		reset_required = true;
	} else if (!(flags & I40EVF_PRIV_FLAGS_PS) &&
		   (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
		adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
		reset_required = true;
	}

	/* if needed, issue reset to cause things to take effect */
	if (reset_required)
		i40evf_schedule_reset(adapter);

	return 0;
}

static const struct ethtool_ops i40evf_ethtool_ops = {
	.get_settings		= i40evf_get_settings,
	.get_drvinfo		= i40evf_get_drvinfo,
@@ -719,6 +782,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = {
	.get_strings		= i40evf_get_strings,
	.get_ethtool_stats	= i40evf_get_ethtool_stats,
	.get_sset_count		= i40evf_get_sset_count,
	.get_priv_flags		= i40evf_get_priv_flags,
	.set_priv_flags		= i40evf_set_priv_flags,
	.get_msglevel		= i40evf_get_msglevel,
	.set_msglevel		= i40evf_set_msglevel,
	.get_coalesce		= i40evf_get_coalesce,
+35 −29
Original line number Diff line number Diff line
@@ -172,6 +172,19 @@ void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
	pr_info("%s", buf);
}

/**
 * i40evf_schedule_reset - Set the flags and schedule a reset event
 * @adapter: board private structure
 **/
void i40evf_schedule_reset(struct i40evf_adapter *adapter)
{
	if (!(adapter->flags &
	      (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) {
		adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
		schedule_work(&adapter->reset_task);
	}
}

/**
 * i40evf_tx_timeout - Respond to a Tx Hang
 * @netdev: network interface device structure
@@ -181,11 +194,7 @@ static void i40evf_tx_timeout(struct net_device *netdev)
	struct i40evf_adapter *adapter = netdev_priv(netdev);

	adapter->tx_timeout_count++;
	if (!(adapter->flags & (I40EVF_FLAG_RESET_PENDING |
				I40EVF_FLAG_RESET_NEEDED))) {
		adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
		queue_work(i40evf_wq, &adapter->reset_task);
	}
	i40evf_schedule_reset(adapter);
}

/**
@@ -638,35 +647,22 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter)
	int rx_buf_len;


	adapter->flags &= ~I40EVF_FLAG_RX_PS_CAPABLE;
	adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;

	/* Decide whether to use packet split mode or not */
	if (netdev->mtu > ETH_DATA_LEN) {
		if (adapter->flags & I40EVF_FLAG_RX_PS_CAPABLE)
			adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
		else
			adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
	} else {
		if (adapter->flags & I40EVF_FLAG_RX_1BUF_CAPABLE)
			adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
		else
			adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
	}

	/* Set the RX buffer length according to the mode */
	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
		rx_buf_len = I40E_RX_HDR_SIZE;
	} else {
		if (netdev->mtu <= ETH_DATA_LEN)
	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ||
	    netdev->mtu <= ETH_DATA_LEN)
		rx_buf_len = I40EVF_RXBUFFER_2048;
	else
		rx_buf_len = ALIGN(max_frame, 1024);
	}

	for (i = 0; i < adapter->num_active_queues; i++) {
		adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i);
		adapter->rx_rings[i].rx_buf_len = rx_buf_len;
		if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
			set_ring_ps_enabled(&adapter->rx_rings[i]);
			adapter->rx_rings[i].rx_hdr_len = I40E_RX_HDR_SIZE;
		} else {
			clear_ring_ps_enabled(&adapter->rx_rings[i]);
		}
	}
}

@@ -1003,7 +999,12 @@ static void i40evf_configure(struct i40evf_adapter *adapter)
	for (i = 0; i < adapter->num_active_queues; i++) {
		struct i40e_ring *ring = &adapter->rx_rings[i];

	if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
		i40evf_alloc_rx_headers(ring);
		i40evf_alloc_rx_buffers_ps(ring, ring->count);
	} else {
		i40evf_alloc_rx_buffers_1buf(ring, ring->count);
	}
		ring->next_to_use = ring->count - 1;
		writel(ring->next_to_use, ring->tail);
	}
@@ -2481,6 +2482,11 @@ static void i40evf_init_task(struct work_struct *work)
	adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;

	adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
	adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;
	adapter->flags |= I40EVF_FLAG_RX_PS_CAPABLE;

	/* Default to single buffer rx, can be changed through ethtool. */
	adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;

	netdev->netdev_ops = &i40evf_netdev_ops;
	i40evf_set_ethtool_ops(netdev);
+4 −0
Original line number Diff line number Diff line
@@ -270,6 +270,10 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter)
		vqpi->rxq.max_pkt_size = adapter->netdev->mtu
					+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
		vqpi->rxq.databuffer_size = adapter->rx_rings[i].rx_buf_len;
		if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
			vqpi->rxq.splithdr_enabled = true;
			vqpi->rxq.hdr_size = I40E_RX_HDR_SIZE;
		}
		vqpi++;
	}