Skip to content

Commit

Permalink
i40evf: support packet split receive
Browse files Browse the repository at this point in the history
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: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Mitch Williams authored and Jeff Kirsher committed Feb 18, 2016
1 parent cb5c260 commit 00e5ec4
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 31 deletions.
6 changes: 5 additions & 1 deletion drivers/net/ethernet/intel/i40evf/i40evf.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* 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,
Expand Down Expand Up @@ -274,13 +274,17 @@ 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[];

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);
Expand Down
67 changes: 66 additions & 1 deletion drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*******************************************************************************
*
* 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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
64 changes: 35 additions & 29 deletions drivers/net/ethernet/intel/i40evf/i40evf_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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)
rx_buf_len = I40EVF_RXBUFFER_2048;
else
rx_buf_len = ALIGN(max_frame, 1024);
}
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]);
}
}
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}

Expand Down

0 comments on commit 00e5ec4

Please sign in to comment.