* [PATCH 1/1] net: Hyper-V: Deletion of an unnecessary check before the function call "vfree"
From: SF Markus Elfring @ 2014-11-20 14:25 UTC (permalink / raw)
To: Haiyang Zhang, K. Y. Srinivasan, devel, netdev
Cc: Julia Lawall, kernel-janitors, LKML
In-Reply-To: <5317A59D.4@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Thu, 20 Nov 2014 15:15:21 +0100
The vfree() function performs also input parameter validation. Thus the test
around the call is not needed.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/net/hyperv/netvsc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index da2d346..ffe7481 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -548,8 +548,7 @@ int netvsc_device_remove(struct hv_device *device)
vmbus_close(device->channel);
/* Release all resources */
- if (net_device->sub_cb_buf)
- vfree(net_device->sub_cb_buf);
+ vfree(net_device->sub_cb_buf);
kfree(net_device);
return 0;
--
2.1.3
^ permalink raw reply related
* [PATCH net-next V1 2/2] net/mlx4_en: Support for configurable RSS hash function
From: Amir Vadai @ 2014-11-20 14:26 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Ben Hutchings, Or Gerlitz, Yevgeny Petrilin, Eyal Perry,
Amir Vadai
In-Reply-To: <1416493610-8966-1-git-send-email-amirv@mellanox.com>
From: Eyal Perry <eyalpe@mellanox.com>
The ConnectX HW is capable of using one of the following hash functions:
Toeplitz and an XOR hash function. This patch extends the implementation
of the mlx4_en driver set/get_rxfh callbacks to support getting and
setting the RSS hash function used by the device.
Signed-off-by: Eyal Perry <eyalpe@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 78 ++++++++++++++++++-------
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 11 ++++
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 13 ++++-
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +-
4 files changed, 80 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index c50181a..ae679ca 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -978,6 +978,27 @@ static u32 mlx4_en_get_rxfh_key_size(struct net_device *netdev)
return MLX4_EN_RSS_KEY_SIZE;
}
+static int mlx4_en_check_rxfh_func(struct net_device *dev, u8 hfunc)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ /* check if requested function is supported by the device */
+ if ((hfunc == ETH_RSS_HASH_TOP &&
+ !(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP)) ||
+ (hfunc == ETH_RSS_HASH_XOR &&
+ !(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR)))
+ return -EINVAL;
+
+ priv->rss_hash_fn = hfunc;
+ if (hfunc == ETH_RSS_HASH_TOP && !(dev->features & NETIF_F_RXHASH))
+ en_warn(priv,
+ "Toeplitz hash function should be used in conjunction with RX hashing for optimal performance\n");
+ if (hfunc == ETH_RSS_HASH_XOR && (dev->features & NETIF_F_RXHASH))
+ en_warn(priv,
+ "Enabling both XOR Hash function and RX Hashing can limit RPS functionality\n");
+ return 0;
+}
+
static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
u8 *hfunc)
{
@@ -987,18 +1008,23 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
size_t n = priv->rx_ring_num;
int err = 0;
- if (!ring_index)
+ if (!ring_index && !hfunc && !key)
return -EOPNOTSUPP;
- rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num;
- rss_rings = 1 << ilog2(rss_rings);
+ if (ring_index) {
+ rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num;
+ rss_rings = 1 << ilog2(rss_rings);
- while (n--) {
- ring_index[n] = rss_map->qps[n % rss_rings].qpn -
- rss_map->base_qpn;
+ while (n--) {
+ ring_index[n] = rss_map->qps[n % rss_rings].qpn -
+ rss_map->base_qpn;
+ }
}
if (key)
netdev_rss_key_fill(key, MLX4_EN_RSS_KEY_SIZE);
+ if (hfunc)
+ *hfunc = priv->rss_hash_fn;
+
return err;
}
@@ -1015,26 +1041,35 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
- if (!ring_index || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ if ((!ring_index && hfunc == ETH_RSS_HASH_NO_CHANGE) || key)
return -EOPNOTSUPP;
- /* Calculate RSS table size and make sure flows are spread evenly
- * between rings
- */
- for (i = 0; i < priv->rx_ring_num; i++) {
- if (i > 0 && !ring_index[i] && !rss_rings)
- rss_rings = i;
+ if (ring_index) {
+ /* Calculate RSS table size and make sure flows are spread
+ * evenly between rings
+ */
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ if (i > 0 && !ring_index[i] && !rss_rings)
+ rss_rings = i;
+
+ if (ring_index[i] != (i % (rss_rings ?:
+ priv->rx_ring_num)))
+ return -EINVAL;
+ }
- if (ring_index[i] != (i % (rss_rings ?: priv->rx_ring_num)))
+ if (!rss_rings)
+ rss_rings = priv->rx_ring_num;
+
+ /* RSS table size must be an order of 2 */
+ if (!is_power_of_2(rss_rings))
return -EINVAL;
}
- if (!rss_rings)
- rss_rings = priv->rx_ring_num;
-
- /* RSS table size must be an order of 2 */
- if (!is_power_of_2(rss_rings))
- return -EINVAL;
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
+ err = mlx4_en_check_rxfh_func(dev, hfunc);
+ if (err)
+ return err;
+ }
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
@@ -1042,7 +1077,8 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
mlx4_en_stop_port(dev, 1);
}
- priv->prof->rss_rings = rss_rings;
+ if (ring_index)
+ priv->prof->rss_rings = rss_rings;
if (port_up) {
err = mlx4_en_start_port(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index f3df9b3..d81bb31 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2596,6 +2596,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
dev->priv_flags |= IFF_UNICAST_FLT;
+ /* Setting a default hash function value */
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP) {
+ priv->rss_hash_fn = ETH_RSS_HASH_TOP;
+ } else if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR) {
+ priv->rss_hash_fn = ETH_RSS_HASH_XOR;
+ } else {
+ en_warn(priv,
+ "No RSS hash capabilities exposed, using Toeplitz\n");
+ priv->rss_hash_fn = ETH_RSS_HASH_TOP;
+ }
+
mdev->pndev[port] = dev;
netif_carrier_off(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index b7bda89..3b3ffbd 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -1223,8 +1223,17 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
rss_context->flags = rss_mask;
rss_context->hash_fn = MLX4_RSS_HASH_TOP;
- netdev_rss_key_fill(rss_context->rss_key, MLX4_EN_RSS_KEY_SIZE);
-
+ if (priv->rss_hash_fn == ETH_RSS_HASH_XOR) {
+ rss_context->hash_fn = MLX4_RSS_HASH_XOR;
+ } else if (priv->rss_hash_fn == ETH_RSS_HASH_TOP) {
+ rss_context->hash_fn = MLX4_RSS_HASH_TOP;
+ netdev_rss_key_fill(rss_context->rss_key,
+ MLX4_EN_RSS_KEY_SIZE);
+ } else {
+ en_err(priv, "Unknown RSS hash function requested\n");
+ err = -EINVAL;
+ goto indir_err;
+ }
err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
&rss_map->indir_qp, &rss_map->indir_state);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index de45674..f08c34c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -376,7 +376,6 @@ struct mlx4_en_port_profile {
};
struct mlx4_en_profile {
- int rss_xor;
int udp_rss;
u8 rss_mask;
u32 active_ports;
@@ -618,6 +617,7 @@ struct mlx4_en_priv {
__be16 vxlan_port;
u32 pflags;
+ u8 rss_hash_fn;
};
enum mlx4_en_wol {
--
1.8.3.4
^ permalink raw reply related
* [PATCH net-next V1 0/2] ethtool, net/mlx4_en: RSS hash function selection
From: Amir Vadai @ 2014-11-20 14:26 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Ben Hutchings, Or Gerlitz, Yevgeny Petrilin, Amir Vadai
Hi,
This patchset by Eyal adds support in set/get of RSS hash function. Current
supported functions are Toeplitz and XOR. The API is design to enable adding
new hash functions without breaking backward compatibility.
Userspace patch will be sent after API is available in kernel.
The patchset was applied and tested over commit 7b909bb ("Merge branches
'core', 'cxgb4', 'iser', 'mlx5' and 'ocrdma' into for-next")
Amir
Changes from V0:
- Patch 1/2 - ethtool: Support for configurable RSS hash function:
- Add ETH prefix to RSS_HASH_* definitions
- Moved the strings array to ethtool.c
- Extend {get,set}_rxfh with additional arg instead of adding new
ethtool_option and adopt the change into drivers implementations.
- Moved indir_size and key_size validation into drivers implantation
- Documented hfunc filed in ethtool_rxfh struct
- Patch 2/2 - net/mlx4_en: Support for configurable RSS hash function
- Remove redundant priv->rss_hash_fn_caps
- Use == operator instead & when determining requested hash function.
Eyal Perry (2):
ethtool: Support for configurable RSS hash function
net/mlx4_en: Support for configurable RSS hash function
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 11 ++-
.../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 14 +++-
drivers/net/ethernet/broadcom/tg3.c | 14 +++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 14 +++-
drivers/net/ethernet/emulex/benet/be_ethtool.c | 14 +++-
drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 14 +++-
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 14 +++-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 14 +++-
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 86 +++++++++++++++++-----
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 11 +++
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 13 +++-
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +-
drivers/net/ethernet/sfc/ethtool.c | 16 +++-
drivers/net/vmxnet3/vmxnet3_ethtool.c | 13 +++-
include/linux/ethtool.h | 42 ++++++++---
include/uapi/linux/ethtool.h | 10 ++-
net/core/ethtool.c | 69 +++++++++--------
17 files changed, 281 insertions(+), 90 deletions(-)
--
1.8.3.4
^ permalink raw reply
* [PATCH net-next V1 1/2] ethtool: Support for configurable RSS hash function
From: Amir Vadai @ 2014-11-20 14:26 UTC (permalink / raw)
To: David S. Miller
Cc: netdev, Ben Hutchings, Or Gerlitz, Yevgeny Petrilin, Eyal Perry,
Tom Lendacky, Ariel Elior, Prashant Sreedharan, Michael Chan,
Hariprasad S, Sathya Perla, Subbu Seetharaman, Ajit Khaparde,
Jeff Kirsher, Jesse Brandeburg, Bruce Allan, Carolyn Wyborny,
Don Skidmore, Greg Rose, Matthew Vick, John Ronciak,
Mitch Williams
In-Reply-To: <1416493610-8966-1-git-send-email-amirv@mellanox.com>
From: Eyal Perry <eyalpe@mellanox.com>
This patch extends the set/get_rxfh ethtool-options for getting or
setting the RSS hash function and modifies drivers implementation of
set/get_rxfh accordingly. This change also delegate the responsibility
of checking weather a modification to a certain RX flow hash parameter
is supported to the driver implementation of set_rxfh.
User-kernel API is done through the new hfunc bitmask field in the
ethtool_rxfh struct. A bit set in the hfunc field is corresponding to an
index in the new string-set ETH_SS_RSS_HASH_FUNCS.
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Ariel Elior <ariel.elior@qlogic.com>
Cc: Prashant Sreedharan <prashant@broadcom.com>
Cc: Michael Chan <mchan@broadcom.com>
Cc: Hariprasad S <hariprasad@chelsio.com>
Cc: Sathya Perla <sathya.perla@emulex.com>
Cc: Subbu Seetharaman <subbu.seetharaman@emulex.com>
Cc: Ajit Khaparde <ajit.khaparde@emulex.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: Jesse Brandeburg <jesse.brandeburg@intel.com>
Cc: Bruce Allan <bruce.w.allan@intel.com>
Cc: Carolyn Wyborny <carolyn.wyborny@intel.com>
Cc: Don Skidmore <donald.c.skidmore@intel.com>
Cc: Greg Rose <gregory.v.rose@intel.com>
Cc: Matthew Vick <matthew.vick@intel.com>
Cc: John Ronciak <john.ronciak@intel.com>
Cc: Mitch Williams <mitch.a.williams@intel.com>
Cc: Amir Vadai <amirv@mellanox.com>
Cc: Solarflare linux maintainers <linux-net-drivers@solarflare.com>
Cc: Shradha Shah <sshah@solarflare.com>
Cc: Shreyas Bhatewara <sbhatewara@vmware.com>
Cc: "VMware, Inc." <pv-drivers@vmware.com>
Cc: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Eyal Perry <eyalpe@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 11 +++-
.../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 14 ++++-
drivers/net/ethernet/broadcom/tg3.c | 14 ++++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 14 ++++-
drivers/net/ethernet/emulex/benet/be_ethtool.c | 14 ++++-
drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 14 ++++-
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 14 ++++-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 14 ++++-
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 14 ++++-
drivers/net/ethernet/sfc/ethtool.c | 16 ++++-
drivers/net/vmxnet3/vmxnet3_ethtool.c | 13 +++-
include/linux/ethtool.h | 42 +++++++++----
include/uapi/linux/ethtool.h | 10 +++-
net/core/ethtool.c | 69 ++++++++++++----------
14 files changed, 204 insertions(+), 69 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index 95d4453..763aec8 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -511,7 +511,8 @@ static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
return ARRAY_SIZE(pdata->rss_table);
}
-static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int i;
@@ -529,12 +530,18 @@ static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
}
static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
unsigned int ret;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if ((!indir && !key) || hfunc != ETH_RSS_HASH_NO_CHANGE)
+ return -EOPNOTSUPP;
+
if (indir) {
ret = hw_if->set_rss_lookup_table(pdata, indir);
if (ret)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 1edc931..654c29e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -3358,12 +3358,16 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev)
return T_ETH_INDIRECTION_TABLE_SIZE;
}
-static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
+static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct bnx2x *bp = netdev_priv(dev);
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
size_t i;
+ if (!indir)
+ return -EOPNOTSUPP;
+
/* Get the current configuration of the RSS indirection table */
bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table);
@@ -3383,11 +3387,17 @@ static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
}
static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct bnx2x *bp = netdev_priv(dev);
size_t i;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!indir || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
/*
* The same as in bnx2x_get_rxfh: we can't use a memcpy()
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 2dc0015..03d168c 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -12560,22 +12560,32 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
return size;
}
-static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
+static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
{
struct tg3 *tp = netdev_priv(dev);
int i;
+ if (!indir)
+ return -EOPNOTSUPP;
+
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
indir[i] = tp->rss_ind_tbl[i];
return 0;
}
-static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key)
+static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
+ const u8 hfunc)
{
struct tg3 *tp = netdev_priv(dev);
size_t i;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!indir || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
tp->rss_ind_tbl[i] = indir[i];
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 19ffe9b..a0c0cbf 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3010,21 +3010,31 @@ static u32 get_rss_table_size(struct net_device *dev)
return pi->rss_size;
}
-static int get_rss_table(struct net_device *dev, u32 *p, u8 *key)
+static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc)
{
const struct port_info *pi = netdev_priv(dev);
unsigned int n = pi->rss_size;
+ if (!p)
+ return -EOPNOTSUPP;
+
while (n--)
p[n] = pi->rss[n];
return 0;
}
-static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key)
+static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key,
+ const u8 hfunc)
{
unsigned int i;
struct port_info *pi = netdev_priv(dev);
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!p || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
for (i = 0; i < pi->rss_size; i++)
pi->rss[i] = p[i];
if (pi->adapter->flags & FULL_INIT_DONE)
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index e42a791..357089f3 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1171,12 +1171,16 @@ static u32 be_get_rxfh_key_size(struct net_device *netdev)
return RSS_HASH_KEY_LEN;
}
-static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
+static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey,
+ u8 *hfunc)
{
struct be_adapter *adapter = netdev_priv(netdev);
int i;
struct rss_info *rss = &adapter->rss_info;
+ if (!indir && !hkey)
+ return -EOPNOTSUPP;
+
if (indir) {
for (i = 0; i < RSS_INDIR_TABLE_LEN; i++)
indir[i] = rss->rss_queue[i];
@@ -1189,12 +1193,18 @@ static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey)
}
static int be_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *hkey)
+ const u8 *hkey, const u8 hfunc)
{
int rc = 0, i, j;
struct be_adapter *adapter = netdev_priv(netdev);
u8 rsstable[RSS_INDIR_TABLE_LEN];
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if ((!indir && !hkey) || hfunc != ETH_RSS_HASH_NO_CHANGE)
+ return -EOPNOTSUPP;
+
if (indir) {
struct be_rx_obj *rxo;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
index 2d04464..352bd8c 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
@@ -916,11 +916,15 @@ static u32 fm10k_get_rssrk_size(struct net_device *netdev)
return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG;
}
-static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key)
+static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
int i, err;
+ if (!indir && !key)
+ return -EOPNOTSUPP;
+
err = fm10k_get_reta(netdev, indir);
if (err || !key)
return err;
@@ -932,12 +936,18 @@ static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key)
}
static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
struct fm10k_hw *hw = &interface->hw;
int i, err;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if ((!indir && !key) || hfunc != ETH_RSS_HASH_NO_CHANGE)
+ return -EOPNOTSUPP;
+
err = fm10k_set_reta(netdev, indir);
if (err || !key)
return err;
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
index 876411c..9ee7847 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
@@ -625,13 +625,17 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
*
* Reads the indirection table directly from the hardware. Always returns 0.
**/
-static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
struct i40e_hw *hw = &adapter->hw;
u32 hlut_val;
int i, j;
+ if (!indir)
+ return -EOPNOTSUPP;
+
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
hlut_val = rd32(hw, I40E_VFQF_HLUT(i));
indir[j++] = hlut_val & 0xff;
@@ -652,13 +656,19 @@ static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
* returns 0 after programming the table.
**/
static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct i40evf_adapter *adapter = netdev_priv(netdev);
struct i40e_hw *hw = &adapter->hw;
u32 hlut_val;
int i, j;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!indir || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
hlut_val = indir[j++];
hlut_val |= indir[j++] << 8;
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 02cfd3b..6cce65a 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2842,11 +2842,15 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev)
return IGB_RETA_SIZE;
}
-static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct igb_adapter *adapter = netdev_priv(netdev);
int i;
+ if (!indir)
+ return -EOPNOTSUPP;
+
for (i = 0; i < IGB_RETA_SIZE; i++)
indir[i] = adapter->rss_indir_tbl[i];
@@ -2889,13 +2893,19 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
int i;
u32 num_queues;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!indir || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
num_queues = adapter->rss_queues;
switch (hw->mac.type) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 710cf30..c50181a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -978,7 +978,8 @@ static u32 mlx4_en_get_rxfh_key_size(struct net_device *netdev)
return MLX4_EN_RSS_KEY_SIZE;
}
-static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
+static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
+ u8 *hfunc)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_rss_map *rss_map = &priv->rss_map;
@@ -986,6 +987,9 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
size_t n = priv->rx_ring_num;
int err = 0;
+ if (!ring_index)
+ return -EOPNOTSUPP;
+
rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num;
rss_rings = 1 << ilog2(rss_rings);
@@ -999,7 +1003,7 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
}
static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
- const u8 *key)
+ const u8 *key, const u8 hfunc)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
@@ -1008,6 +1012,12 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
int i;
int rss_rings = 0;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!ring_index || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
/* Calculate RSS table size and make sure flows are spread evenly
* between rings
*/
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index cad258a..f5f953c 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -1086,19 +1086,29 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
0 : ARRAY_SIZE(efx->rx_indir_table));
}
-static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key)
+static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ if (!indir)
+ return -EOPNOTSUPP;
+
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
return 0;
}
-static int efx_ethtool_set_rxfh(struct net_device *net_dev,
- const u32 *indir, const u8 *key)
+static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!indir || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table));
efx->type->rx_push_rss_config(efx);
return 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index b725fd9..5a148cb 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -583,12 +583,14 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev)
}
static int
-vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key)
+vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key, u8 *hfunc)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
unsigned int n = rssConf->indTableSize;
+ if (!p)
+ return -EOPNOTSUPP;
while (n--)
p[n] = rssConf->indTable[n];
return 0;
@@ -596,13 +598,20 @@ vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key)
}
static int
-vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key)
+vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key,
+ const u8 hfunc)
{
unsigned int i;
unsigned long flags;
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+ /* We require at least one supported parameter to be changed and no
+ * change in any of the unsupported parameters
+ */
+ if (!p || (key || hfunc != ETH_RSS_HASH_NO_CHANGE))
+ return -EOPNOTSUPP;
+
for (i = 0; i < rssConf->indTableSize; i++)
rssConf->indTable[i] = p[i];
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index c1a2d60..653dc9c 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -59,6 +59,26 @@ enum ethtool_phys_id_state {
ETHTOOL_ID_OFF
};
+enum {
+ ETH_RSS_HASH_TOP_BIT, /* Configurable RSS hash function - Toeplitz */
+ ETH_RSS_HASH_XOR_BIT, /* Configurable RSS hash function - Xor */
+
+ /*
+ * Add your fresh new hash function bits above and remember to update
+ * rss_hash_func_strings[] in ethtool.c
+ */
+ ETH_RSS_HASH_FUNCS_COUNT
+};
+
+#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
+#define __ETH_RSS_HASH(name) __ETH_RSS_HASH_BIT(ETH_RSS_HASH_##name##_BIT)
+
+#define ETH_RSS_HASH_TOP __ETH_RSS_HASH(TOP)
+#define ETH_RSS_HASH_XOR __ETH_RSS_HASH(XOR)
+
+#define ETH_RSS_HASH_UNKNOWN 0
+#define ETH_RSS_HASH_NO_CHANGE 0
+
struct net_device;
/* Some generic methods drivers may use in their ethtool_ops */
@@ -158,17 +178,14 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
* Returns zero if not supported for this specific device.
* @get_rxfh_indir_size: Get the size of the RX flow hash indirection table.
* Returns zero if not supported for this specific device.
- * @get_rxfh: Get the contents of the RX flow hash indirection table and hash
- * key.
- * Will only be called if one or both of @get_rxfh_indir_size and
- * @get_rxfh_key_size are implemented and return non-zero.
- * Returns a negative error code or zero.
- * @set_rxfh: Set the contents of the RX flow hash indirection table and/or
- * hash key. In case only the indirection table or hash key is to be
- * changed, the other argument will be %NULL.
- * Will only be called if one or both of @get_rxfh_indir_size and
- * @get_rxfh_key_size are implemented and return non-zero.
+ * @get_rxfh: Get the contents of the RX flow hash indirection table, hash key
+ * and/or hash function.
* Returns a negative error code or zero.
+ * @set_rxfh: Set the contents of the RX flow hash indirection table, hash
+ * key, and/or hash function. Arguments which are set to %NULL or zero
+ * will remain unchanged.
+ * Returns a negative error code or zero. An error code must be returned
+ * if at least one unsupported change was requested.
* @get_channels: Get number of channels.
* @set_channels: Set number of channels. Returns a negative error code or
* zero.
@@ -241,9 +258,10 @@ struct ethtool_ops {
int (*reset)(struct net_device *, u32 *);
u32 (*get_rxfh_key_size)(struct net_device *);
u32 (*get_rxfh_indir_size)(struct net_device *);
- int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key);
+ int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key,
+ u8 *hfunc);
int (*set_rxfh)(struct net_device *, const u32 *indir,
- const u8 *key);
+ const u8 *key, const u8 hfunc);
void (*get_channels)(struct net_device *, struct ethtool_channels *);
int (*set_channels)(struct net_device *, struct ethtool_channels *);
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index eb2095b..5f66d9c 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -534,6 +534,7 @@ struct ethtool_pauseparam {
* @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE;
* now deprecated
* @ETH_SS_FEATURES: Device feature names
+ * @ETH_SS_RSS_HASH_FUNCS: RSS hush function names
*/
enum ethtool_stringset {
ETH_SS_TEST = 0,
@@ -541,6 +542,7 @@ enum ethtool_stringset {
ETH_SS_PRIV_FLAGS,
ETH_SS_NTUPLE_FILTERS,
ETH_SS_FEATURES,
+ ETH_SS_RSS_HASH_FUNCS,
};
/**
@@ -884,6 +886,8 @@ struct ethtool_rxfh_indir {
* @key_size: On entry, the array size of the user buffer for the hash key,
* which may be zero. On return from %ETHTOOL_GRSSH, the size of the
* hardware hash key.
+ * @hfunc: Defines the current RSS hash function used by HW (or to be set to).
+ * Valid values are one of the %ETH_RSS_HASH_*.
* @rsvd: Reserved for future extensions.
* @rss_config: RX ring/queue index for each hash value i.e., indirection table
* of @indir_size __u32 elements, followed by hash key of @key_size
@@ -893,14 +897,16 @@ struct ethtool_rxfh_indir {
* size should be returned. For %ETHTOOL_SRSSH, an @indir_size of
* %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
* and a @indir_size of zero means the indir table should be reset to default
- * values.
+ * values. An hfunc of zero means that hash function setting is not requested.
*/
struct ethtool_rxfh {
__u32 cmd;
__u32 rss_context;
__u32 indir_size;
__u32 key_size;
- __u32 rsvd[2];
+ __u8 hfunc;
+ __u8 rsvd8[3];
+ __u32 rsvd32;
__u32 rss_config[0];
};
#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 715f51f..550892c 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -100,6 +100,12 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_BUSY_POLL_BIT] = "busy-poll",
};
+static const char
+rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
+ [ETH_RSS_HASH_TOP_BIT] = "toeplitz",
+ [ETH_RSS_HASH_XOR_BIT] = "xor",
+};
+
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{
struct ethtool_gfeatures cmd = {
@@ -185,6 +191,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
if (sset == ETH_SS_FEATURES)
return ARRAY_SIZE(netdev_features_strings);
+ if (sset == ETH_SS_RSS_HASH_FUNCS)
+ return ARRAY_SIZE(rss_hash_func_strings);
+
if (ops->get_sset_count && ops->get_strings)
return ops->get_sset_count(dev, sset);
else
@@ -199,6 +208,9 @@ static void __ethtool_get_strings(struct net_device *dev,
if (stringset == ETH_SS_FEATURES)
memcpy(data, netdev_features_strings,
sizeof(netdev_features_strings));
+ else if (stringset == ETH_SS_RSS_HASH_FUNCS)
+ memcpy(data, rss_hash_func_strings,
+ sizeof(rss_hash_func_strings));
else
/* ops->get_strings is valid because checked earlier */
ops->get_strings(dev, stringset, data);
@@ -618,7 +630,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
if (!indir)
return -ENOMEM;
- ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL);
+ ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
if (ret)
goto out;
@@ -679,7 +691,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
goto out;
}
- ret = ops->set_rxfh(dev, indir, NULL);
+ ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
out:
kfree(indir);
@@ -697,12 +709,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
u32 total_size;
u32 indir_bytes;
u32 *indir = NULL;
+ u8 dev_hfunc = 0;
u8 *hkey = NULL;
u8 *rss_config;
- if (!(dev->ethtool_ops->get_rxfh_indir_size ||
- dev->ethtool_ops->get_rxfh_key_size) ||
- !dev->ethtool_ops->get_rxfh)
+ if (!ops->get_rxfh)
return -EOPNOTSUPP;
if (ops->get_rxfh_indir_size)
@@ -710,16 +721,14 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
if (ops->get_rxfh_key_size)
dev_key_size = ops->get_rxfh_key_size(dev);
- if ((dev_key_size + dev_indir_size) == 0)
- return -EOPNOTSUPP;
-
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
return -EFAULT;
user_indir_size = rxfh.indir_size;
user_key_size = rxfh.key_size;
/* Check that reserved fields are 0 for now */
- if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
+ if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
+ rxfh.rsvd8[2] || rxfh.rsvd32)
return -EINVAL;
rxfh.indir_size = dev_indir_size;
@@ -727,13 +736,6 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
return -EFAULT;
- /* If the user buffer size is 0, this is just a query for the
- * device table size and key size. Otherwise, if the User size is
- * not equal to device table size or key size it's an error.
- */
- if (!user_indir_size && !user_key_size)
- return 0;
-
if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
(user_key_size && (user_key_size != dev_key_size)))
return -EINVAL;
@@ -750,14 +752,19 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
if (user_key_size)
hkey = rss_config + indir_bytes;
- ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey);
- if (!ret) {
- if (copy_to_user(useraddr +
- offsetof(struct ethtool_rxfh, rss_config[0]),
- rss_config, total_size))
- ret = -EFAULT;
- }
+ ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
+ if (ret)
+ goto out;
+ if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
+ &dev_hfunc, sizeof(rxfh.hfunc))) {
+ ret = -EFAULT;
+ } else if (copy_to_user(useraddr +
+ offsetof(struct ethtool_rxfh, rss_config[0]),
+ rss_config, total_size)) {
+ ret = -EFAULT;
+ }
+out:
kfree(rss_config);
return ret;
@@ -776,33 +783,31 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
u8 *rss_config;
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
- if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) ||
- !ops->get_rxnfc || !ops->set_rxfh)
+ if (!ops->get_rxnfc || !ops->set_rxfh)
return -EOPNOTSUPP;
if (ops->get_rxfh_indir_size)
dev_indir_size = ops->get_rxfh_indir_size(dev);
if (ops->get_rxfh_key_size)
dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
- if ((dev_key_size + dev_indir_size) == 0)
- return -EOPNOTSUPP;
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
return -EFAULT;
/* Check that reserved fields are 0 for now */
- if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1])
+ if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
+ rxfh.rsvd8[2] || rxfh.rsvd32)
return -EINVAL;
- /* If either indir or hash key is valid, proceed further.
- * It is not valid to request that both be unchanged.
+ /* If either indir, hash key or function is valid, proceed further.
+ * Must request at least one change: indir size, hash key or function.
*/
if ((rxfh.indir_size &&
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
rxfh.indir_size != dev_indir_size) ||
(rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
(rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
- rxfh.key_size == 0))
+ rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
return -EINVAL;
if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
@@ -845,7 +850,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
}
}
- ret = ops->set_rxfh(dev, indir, hkey);
+ ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
out:
kfree(rss_config);
--
1.8.3.4
^ permalink raw reply related
* Re: [PATCH net-next V1 0/2] ethtool, net/mlx4_en: RSS hash function selection
From: Amir Vadai @ 2014-11-20 14:34 UTC (permalink / raw)
To: Amir Vadai
Cc: David S. Miller, netdev, Ben Hutchings, Or Gerlitz,
Yevgeny Petrilin
In-Reply-To: <1416493610-8966-1-git-send-email-amirv@mellanox.com>
On Thu, Nov 20, 2014 at 4:26 PM, Amir Vadai <amirv@mellanox.com> wrote:
> Hi,
>
> This patchset by Eyal adds support in set/get of RSS hash function. Current
> supported functions are Toeplitz and XOR. The API is design to enable adding
> new hash functions without breaking backward compatibility.
> Userspace patch will be sent after API is available in kernel.
>
> The patchset was applied and tested over commit 7b909bb ("Merge branches
> 'core', 'cxgb4', 'iser', 'mlx5' and 'ocrdma' into for-next")
Should be commit daaf427 ("bpf: fix arraymap NULL deref and missing
overflow and zero size checks")
>
> Amir
>
[...]
^ permalink raw reply
* [PATCH 1/2] net/am2150: fix nmclan_cs.c shared interrupt handling
From: Arnd Bergmann @ 2014-11-20 15:11 UTC (permalink / raw)
To: netdev; +Cc: Jeff Kirsher, Roger Pao, linux-kernel, linux-pcmcia
A recent patch tried to work around a valid warning for the use of a
deprecated interface by blindly changing from the old
pcmcia_request_exclusive_irq() interface to pcmcia_request_irq().
This driver has an interrupt handler that is not currently aware
of shared interrupts, but can be easily converted to be.
At the moment, the driver reads the interrupt status register
repeatedly until it contains only zeroes in the interesting bits,
and handles each bit individually.
This patch adds the missing part of returning IRQ_NONE in case none
of the bits are set to start with, so we can move on to the next
interrupt source.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 5f5316fcd08ef7 ("am2150: Update nmclan_cs.c to use update PCMCIA API")
---
I had this patch in my queue of things to submit and noticed that
the warning had gone away upstream but my patch was still there.
For all I can tell, the driver is broken without this, although it
would rarely be a problem.
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 5b22764ba88d..27245efe9f50 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -952,6 +952,8 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
do {
/* WARNING: MACE_IR is a READ/CLEAR port! */
status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
+ if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS)
+ return IRQ_NONE;
pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
^ permalink raw reply related
* [PATCH 1/1] net: USB: Deletion of unnecessary checks before the function call "kfree"
From: SF Markus Elfring @ 2014-11-20 15:16 UTC (permalink / raw)
To: Jan Dumon, linux-usb, netdev; +Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <5317A59D.4@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Thu, 20 Nov 2014 16:11:56 +0100
The kfree() function tests whether its argument is NULL and then
returns immediately. Thus the test around the call is not needed.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/net/usb/asix_devices.c | 3 +--
drivers/net/usb/hso.c | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 5d19409..8a7582b 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -499,8 +499,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
{
- if (dev->driver_priv)
- kfree(dev->driver_priv);
+ kfree(dev->driver_priv);
}
static const struct ethtool_ops ax88178_ethtool_ops = {
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index babda7d..9c5aa92 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2746,8 +2746,7 @@ exit:
tty_unregister_device(tty_drv, serial->minor);
kfree(serial);
}
- if (hso_dev)
- kfree(hso_dev);
+ kfree(hso_dev);
return NULL;
}
--
2.1.3
^ permalink raw reply related
* [PATCH 2/2] pcmcia: remove pcmcia_request_exclusive_irq
From: Arnd Bergmann @ 2014-11-20 15:21 UTC (permalink / raw)
To: netdev; +Cc: Jeff Kirsher, Roger Pao, linux-kernel, linux-pcmcia
In-Reply-To: <4353896.15JnC91eLO@wuerfel>
The last user of the deprecated pcmcia_request_exclusive_irq function,
was removed in 5f5316fcd08e ("am2150: Update nmclan_cs.c to use update
PCMCIA API"), so we can clean up the core code and remove the interface
and its documentation.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
Documentation/pcmcia/driver-changes.txt | 3 ---
drivers/pcmcia/pcmcia_resource.c | 39 ---------------------------------------
include/pcmcia/ds.h | 10 ----------
3 files changed, 0 insertions(+), 52 deletions(-)
---
The patch that removed the last user was merged in 3.18-rc1, so this
should be safe to apply independently now.
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index dd04361dd361..78355c4c268a 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -46,9 +46,6 @@ This file details changes in 2.6 which affect PCMCIA card driver authors:
- use pcmcia_request_irq(p_dev, handler_t); the PCMCIA core will
clean up automatically on calls to pcmcia_disable_device() or
device ejection.
- - drivers still not capable of IRQF_SHARED (or not telling us so) may
- use the deprecated pcmcia_request_exclusive_irq() for the time
- being; they might receive a shared IRQ nonetheless.
* no cs_error / CS_CHECK / CONFIG_PCMCIA_DEBUG (as of 2.6.33)
Instead of the cs_error() callback or the CS_CHECK() macro, please use
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index e8c19def1b0f..23a123da3dd7 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -712,45 +712,6 @@ int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
}
EXPORT_SYMBOL(pcmcia_request_irq);
-
-/**
- * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first
- * @p_dev: the associated PCMCIA device
- * @handler: IRQ handler to register
- *
- * pcmcia_request_exclusive_irq() is a wrapper around request_irq() which
- * attempts first to request an exclusive IRQ. If it fails, it also accepts
- * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for
- * IRQ sharing and either use request_irq directly (then they need to call
- * free_irq() themselves, too), or the pcmcia_request_irq() function.
- */
-int __must_check
-__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
- irq_handler_t handler)
-{
- int ret;
-
- if (!p_dev->irq)
- return -EINVAL;
-
- ret = request_irq(p_dev->irq, handler, 0, p_dev->devname, p_dev->priv);
- if (ret) {
- ret = pcmcia_request_irq(p_dev, handler);
- dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
- "request for exclusive IRQ could not be fulfilled.\n");
- dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
- "needs updating to supported shared IRQ lines.\n");
- }
- if (ret)
- dev_printk(KERN_INFO, &p_dev->dev, "request_irq() failed\n");
- else
- p_dev->_irq = 1;
-
- return ret;
-} /* pcmcia_request_exclusive_irq */
-EXPORT_SYMBOL(__pcmcia_request_exclusive_irq);
-
-
#ifdef CONFIG_PCMCIA_PROBE
/* mask of IRQs already reserved by other cards, we should avoid using them */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 2d56e428506c..3037157855f0 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -206,16 +206,6 @@ int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val);
/* device configuration */
int pcmcia_request_io(struct pcmcia_device *p_dev);
-int __must_check
-__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
- irq_handler_t handler);
-static inline __must_check __deprecated int
-pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
- irq_handler_t handler)
-{
- return __pcmcia_request_exclusive_irq(p_dev, handler);
-}
-
int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
irq_handler_t handler);
^ permalink raw reply related
* Re: Question on bulk dequeue support in virtual drivers
From: Eric Dumazet @ 2014-11-20 15:26 UTC (permalink / raw)
To: James Yonan; +Cc: Linux Netdev List
In-Reply-To: <546DE110.8060607@openvpn.net>
On Thu, 2014-11-20 at 05:39 -0700, James Yonan wrote:
> Consider a tunneling driver that receives packets in ndo_start_xmit,
> encapsulates them in UDP, and forwards via ip_local_out. The
> ndo_start_xmit implementation can implement bulking by looking at
> skb->xmit_more. But then how to efficiently transmit the resulting
> bulked list of encapsulated packets via UDP, so that the packets both
> enter and leave the driver in bulked form? Is there an ip_local_out
> alternative for bulked skb lists?
There is no such thing. Quite frankly it wont happen. Consider IP stacks
and netfilter, there is no provision for batches (other than GSO/TSO)
xmit_more addresses a specific hardware problem, it is not an
alternative for batches.
xmit_more will happen in your case in the last step, from qdisc to
ethernet device.
^ permalink raw reply
* Re: [PATCH v2 net-next] tcp: make connect() mem charging friendly
From: Eric Dumazet @ 2014-11-20 15:33 UTC (permalink / raw)
To: David Miller; +Cc: ycheng, nuclearcat, netdev, ncardwell
In-Reply-To: <20141119.145741.1905980604994551607.davem@davemloft.net>
On Wed, 2014-11-19 at 14:57 -0500, David Miller wrote:
> From: Yuchung Cheng <ycheng@google.com>
> >
> > Thanks! this simplifies the code a lot.
>
> Agreed, applied, thanks everyone!
BTW, unless I am mistaken, it seems we can probably replace
memcpy_fromiovecend() by memcpy_fromiovec() and delete from
tcp_sendmsg() the annoying code skipping over the already consumed
bytes.
Something like this untested patch :
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c239f4740d10b10b67ef4fa44c831851fb9e1dcf..227540eef9d0870721258f9ddbace27b417c619e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1089,20 +1089,19 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags, err, copied = 0;
- int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
+ int mss_now = 0, size_goal, copied_syn = 0;
bool sg;
long timeo;
lock_sock(sk);
flags = msg->msg_flags;
- if (flags & MSG_FASTOPEN) {
+ if (unlikely(flags & MSG_FASTOPEN)) {
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
if (err == -EINPROGRESS && copied_syn > 0)
goto out;
else if (err)
goto out_err;
- offset = copied_syn;
}
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -1151,15 +1150,6 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
unsigned char __user *from = iov->iov_base;
iov++;
- if (unlikely(offset > 0)) { /* Skip bytes copied in SYN */
- if (offset >= seglen) {
- offset -= seglen;
- continue;
- }
- seglen -= offset;
- from += offset;
- offset = 0;
- }
while (seglen > 0) {
int copy = 0;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f5bd4bd3f7e669b3fd48a843d55e7313a30a3409..524e5b657e881a348f11def3f48f29a76f54fbab 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3049,8 +3049,8 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
goto fallback;
syn_data->ip_summed = CHECKSUM_PARTIAL;
memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
- if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space),
- fo->data->msg_iov, 0, space))) {
+ if (unlikely(memcpy_fromiovec(skb_put(syn_data, space),
+ fo->data->msg_iov, space))) {
kfree_skb(syn_data);
goto fallback;
}
^ permalink raw reply related
* [PATCH 1/1] net: brcm80211: Deletion of unnecessary checks before two function calls
From: SF Markus Elfring @ 2014-11-20 15:50 UTC (permalink / raw)
To: Arend van Spriel, Brett Rudley, Franky (Zhenhui) Lin,
Hante Meuleman, John W. Linville, linux-wireless,
brcm80211-dev-list, netdev
Cc: LKML, kernel-janitors, Julia Lawall
In-Reply-To: <5317A59D.4@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Thu, 20 Nov 2014 16:42:51 +0100
The functions brcmu_pkt_buf_free_skb() and release_firmware() test whether
their argument is NULL and then return immediately. Thus the test around
the call is not needed.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 3 +--
drivers/net/wireless/brcm80211/brcmfmac/firmware.c | 3 +--
drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 3 +--
drivers/net/wireless/brcm80211/brcmsmac/main.c | 3 +--
4 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index f55f625..8ff7037 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -2539,8 +2539,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
/* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
+ brcmu_pkt_buf_free_skb(bus->glomd);
brcmf_sdio_free_glom(bus);
/* Clear rx control and wake any waiters */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 8ea9f28..3a2d014 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -262,8 +262,7 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
fail:
brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
- if (fwctx->code)
- release_firmware(fwctx->code);
+ release_firmware(fwctx->code);
device_release_driver(fwctx->dev);
kfree(fwctx);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index 8f8b937..0cb00dc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -506,8 +506,7 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?
len : msgbuf->ioctl_resp_ret_len);
}
- if (skb)
- brcmu_pkt_buf_free_skb(skb);
+ brcmu_pkt_buf_free_skb(skb);
return msgbuf->ioctl_resp_status;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 1b47482..ce538a1 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -1009,8 +1009,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
if (txh)
trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
sizeof(*txh));
- if (p)
- brcmu_pkt_buf_free_skb(p);
+ brcmu_pkt_buf_free_skb(p);
}
if (dma && queue < NFIFO) {
--
2.1.3
^ permalink raw reply related
* Re: [patch net-next v2 02/10] net: introduce generic switch devices support
From: Andy Gospodarek @ 2014-11-20 15:55 UTC (permalink / raw)
To: Roopa Prabhu
Cc: Jiri Pirko, netdev, davem, nhorman, andy, tgraf, dborkman,
ogerlitz, jesse, pshelar, azhou, ben, stephen, jeffrey.t.kirsher,
vyasevic, xiyou.wangcong, john.r.fastabend, edumazet, jhs,
sfeldma, f.fainelli, linville, jasowang, ebiederm,
nicolas.dichtel, ryazanov.s.a, buytenh, aviadr, nbd,
alexei.starovoitov, Neil.Jerram, ronye, simon.horman,
alexander.h.duyck, john.ronciak, mleitner, shrijeet, bcrl
In-Reply-To: <546CA237.3010600@cumulusnetworks.com>
On Wed, Nov 19, 2014 at 05:59:19AM -0800, Roopa Prabhu wrote:
> On 11/19/14, 5:46 AM, Jiri Pirko wrote:
> >Wed, Nov 19, 2014 at 02:28:10PM CET, roopa@cumulusnetworks.com wrote:
> >>On 11/9/14, 2:51 AM, Jiri Pirko wrote:
> >>>The goal of this is to provide a possibility to support various switch
> >>>chips. Drivers should implement relevant ndos to do so. Now there is
> >>>only one ndo defined:
> >>>- for getting physical switch id is in place.
> >>>
> >>>Note that user can use random port netdevice to access the switch.
> >>>
> >>>Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> >>>---
> >>> Documentation/networking/switchdev.txt | 59 ++++++++++++++++++++++++++++++++++
> >>> MAINTAINERS | 7 ++++
> >>> include/linux/netdevice.h | 10 ++++++
> >>> include/net/switchdev.h | 30 +++++++++++++++++
> >>> net/Kconfig | 1 +
> >>> net/Makefile | 3 ++
> >>> net/switchdev/Kconfig | 13 ++++++++
> >>> net/switchdev/Makefile | 5 +++
> >>> net/switchdev/switchdev.c | 33 +++++++++++++++++++
> >>> 9 files changed, 161 insertions(+)
> >>> create mode 100644 Documentation/networking/switchdev.txt
> >>> create mode 100644 include/net/switchdev.h
> >>> create mode 100644 net/switchdev/Kconfig
> >>> create mode 100644 net/switchdev/Makefile
> >>> create mode 100644 net/switchdev/switchdev.c
> >>>
> >>>diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt
> >>>new file mode 100644
> >>>index 0000000..98be76c
> >>>--- /dev/null
> >>>+++ b/Documentation/networking/switchdev.txt
> >>>@@ -0,0 +1,59 @@
> >>>+Switch (and switch-ish) device drivers HOWTO
> >>>+===========================
> >>>+
> >>>+Please note that the word "switch" is here used in very generic meaning.
> >>>+This include devices supporting L2/L3 but also various flow offloading chips,
> >>>+including switches embedded into SR-IOV NICs.
> >>>+
> >>>+Lets describe a topology a bit. Imagine the following example:
> >>>+
> >>>+ +----------------------------+ +---------------+
> >>>+ | SOME switch chip | | CPU |
> >>>+ +----------------------------+ +---------------+
> >>>+ port1 port2 port3 port4 MNGMNT | PCI-E |
> >>>+ | | | | | +---------------+
> >>>+ PHY PHY | | | | NIC0 NIC1
> >>>+ | | | | | |
> >>>+ | | +- PCI-E -+ | |
> >>>+ | +------- MII -------+ |
> >>>+ +------------- MII ------------+
> >>>+
> >>>+In this example, there are two independent lines between the switch silicon
> >>>+and CPU. NIC0 and NIC1 drivers are not aware of a switch presence. They are
> >>>+separate from the switch driver. SOME switch chip is by managed by a driver
> >>>+via PCI-E device MNGMNT. Note that MNGMNT device, NIC0 and NIC1 may be
> >>>+connected to some other type of bus.
> >>>+
> >>>+Now, for the previous example show the representation in kernel:
> >>>+
> >>>+ +----------------------------+ +---------------+
> >>>+ | SOME switch chip | | CPU |
> >>>+ +----------------------------+ +---------------+
> >>>+ sw0p0 sw0p1 sw0p2 sw0p3 MNGMNT | PCI-E |
> >>>+ | | | | | +---------------+
> >>>+ PHY PHY | | | | eth0 eth1
> >>>+ | | | | | |
> >>>+ | | +- PCI-E -+ | |
> >>>+ | +------- MII -------+ |
> >>>+ +------------- MII ------------+
> >>>+
> >>>+Lets call the example switch driver for SOME switch chip "SOMEswitch". This
> >>>+driver takes care of PCI-E device MNGMNT. There is a netdevice instance sw0pX
> >>>+created for each port of a switch. These netdevices are instances
> >>>+of "SOMEswitch" driver. sw0pX netdevices serve as a "representation"
> >>>+of the switch chip. eth0 and eth1 are instances of some other existing driver.
> >>>+
> >>>+The only difference of the switch-port netdevice from the ordinary netdevice
> >>>+is that is implements couple more NDOs:
> >>>+
> >>>+ ndo_sw_parent_get_id - This returns the same ID for two port netdevices
> >>>+ of the same physical switch chip. This is
> >>>+ mandatory to be implemented by all switch drivers
> >>>+ and serves the caller for recognition of a port
> >>>+ netdevice.
> >>>+ ndo_sw_parent_* - Functions that serve for a manipulation of the switch
> >>>+ chip itself (it can be though of as a "parent" of the
> >>>+ port, therefore the name). They are not port-specific.
> >>>+ Caller might use arbitrary port netdevice of the same
> >>>+ switch and it will make no difference.
> >>>+ ndo_sw_port_* - Functions that serve for a port-specific manipulation.
> >>>diff --git a/MAINTAINERS b/MAINTAINERS
> >>>index 3a41fb0..776e078 100644
> >>>--- a/MAINTAINERS
> >>>+++ b/MAINTAINERS
> >>>@@ -9003,6 +9003,13 @@ F: lib/swiotlb.c
> >>> F: arch/*/kernel/pci-swiotlb.c
> >>> F: include/linux/swiotlb.h
> >>>+SWITCHDEV
> >>>+M: Jiri Pirko <jiri@resnulli.us>
> >>>+L: netdev@vger.kernel.org
> >>>+S: Supported
> >>>+F: net/switchdev/
> >>>+F: include/net/switchdev.h
> >>>+
> >>> SYNOPSYS ARC ARCHITECTURE
> >>> M: Vineet Gupta <vgupta@synopsys.com>
> >>> S: Supported
> >>>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> >>>index 71922e0..97eade9 100644
> >>>--- a/include/linux/netdevice.h
> >>>+++ b/include/linux/netdevice.h
> >>>@@ -1017,6 +1017,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
> >>> * performing GSO on a packet. The device returns true if it is
> >>> * able to GSO the packet, false otherwise. If the return value is
> >>> * false the stack will do software GSO.
> >>>+ *
> >>>+ * int (*ndo_sw_parent_id_get)(struct net_device *dev,
> >>>+ * struct netdev_phys_item_id *psid);
> >>>+ * Called to get an ID of the switch chip this port is part of.
> >>>+ * If driver implements this, it indicates that it represents a port
> >>>+ * of a switch chip.
> >>> */
> >>> struct net_device_ops {
> >>> int (*ndo_init)(struct net_device *dev);
> >>>@@ -1168,6 +1174,10 @@ struct net_device_ops {
> >>> int (*ndo_get_lock_subclass)(struct net_device *dev);
> >>> bool (*ndo_gso_check) (struct sk_buff *skb,
> >>> struct net_device *dev);
> >>>+#ifdef CONFIG_NET_SWITCHDEV
> >>>+ int (*ndo_sw_parent_id_get)(struct net_device *dev,
> >>>+ struct netdev_phys_item_id *psid);
> >>Can we keep the name generic and not include "sw" which implies switch here
> >>?.
> >>I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for
> >>them in other offload scenarios in the future.
> >>This particular ndo can be just ndo_parent_id_get().
> >>And the others that do specific offloads can have "offload" in them if
> >>required..?.
> >
> >But this is for getting parent switch id, sw should be there.
>
> Since we have not figured out the details or namespace for switchd ids yet,
> its still some parent id to me.
>
> >If comes a
> >time when this might be reused to something else, we change it then.
> >This is internal api, easily changeable.
> also, "sw" seems more "software" than "switch".
I had voiced this same concern when we met and discussed this in
Dusseldorf. Let's move to another name such as 'hw' (since we really
are talking about hardware abstraction) or 'offload.' Just using 'sw'
is confusing as many will not read it as switch.
I'll be happy to post a fix based on your devel patches.
>
> >
> >>
> >>
> >>>+#endif
> >>> };
> >>> /**
> >>>diff --git a/include/net/switchdev.h b/include/net/switchdev.h
> >>>new file mode 100644
> >>>index 0000000..79bf9bd
> >>>--- /dev/null
> >>>+++ b/include/net/switchdev.h
> >>>@@ -0,0 +1,30 @@
> >>>+/*
> >>>+ * include/net/switchdev.h - Switch device API
> >>>+ * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
> >>>+ *
> >>>+ * This program is free software; you can redistribute it and/or modify
> >>>+ * it under the terms of the GNU General Public License as published by
> >>>+ * the Free Software Foundation; either version 2 of the License, or
> >>>+ * (at your option) any later version.
> >>>+ */
> >>>+#ifndef _LINUX_SWITCHDEV_H_
> >>>+#define _LINUX_SWITCHDEV_H_
> >>>+
> >>>+#include <linux/netdevice.h>
> >>>+
> >>>+#ifdef CONFIG_NET_SWITCHDEV
> >>>+
> >>>+int netdev_sw_parent_id_get(struct net_device *dev,
> >>>+ struct netdev_phys_item_id *psid);
> >>>+
> >>>+#else
> >>>+
> >>>+static inline int netdev_sw_parent_id_get(struct net_device *dev,
> >>>+ struct netdev_phys_item_id *psid)
> >>>+{
> >>>+ return -EOPNOTSUPP;
> >>>+}
> >>>+
> >>>+#endif
> >>>+
> >>>+#endif /* _LINUX_SWITCHDEV_H_ */
> >>>diff --git a/net/Kconfig b/net/Kconfig
> >>>index 99815b5..ff9ffc1 100644
> >>>--- a/net/Kconfig
> >>>+++ b/net/Kconfig
> >>>@@ -228,6 +228,7 @@ source "net/vmw_vsock/Kconfig"
> >>> source "net/netlink/Kconfig"
> >>> source "net/mpls/Kconfig"
> >>> source "net/hsr/Kconfig"
> >>>+source "net/switchdev/Kconfig"
> >>> config RPS
> >>> boolean
> >>>diff --git a/net/Makefile b/net/Makefile
> >>>index 7ed1970..95fc694 100644
> >>>--- a/net/Makefile
> >>>+++ b/net/Makefile
> >>>@@ -73,3 +73,6 @@ obj-$(CONFIG_OPENVSWITCH) += openvswitch/
> >>> obj-$(CONFIG_VSOCKETS) += vmw_vsock/
> >>> obj-$(CONFIG_NET_MPLS_GSO) += mpls/
> >>> obj-$(CONFIG_HSR) += hsr/
> >>>+ifneq ($(CONFIG_NET_SWITCHDEV),)
> >>>+obj-y += switchdev/
> >>>+endif
> >>>diff --git a/net/switchdev/Kconfig b/net/switchdev/Kconfig
> >>>new file mode 100644
> >>>index 0000000..1557545
> >>>--- /dev/null
> >>>+++ b/net/switchdev/Kconfig
> >>>@@ -0,0 +1,13 @@
> >>>+#
> >>>+# Configuration for Switch device support
> >>>+#
> >>>+
> >>>+config NET_SWITCHDEV
> >>>+ boolean "Switch (and switch-ish) device support (EXPERIMENTAL)"
> >>>+ depends on INET
> >>>+ ---help---
> >>>+ This module provides glue between core networking code and device
> >>>+ drivers in order to support hardware switch chips in very generic
> >>>+ meaning of the word "switch". This include devices supporting L2/L3 but
> >>>+ also various flow offloading chips, including switches embedded into
> >>>+ SR-IOV NICs.
> >>>diff --git a/net/switchdev/Makefile b/net/switchdev/Makefile
> >>>new file mode 100644
> >>>index 0000000..5ed63ed
> >>>--- /dev/null
> >>>+++ b/net/switchdev/Makefile
> >>>@@ -0,0 +1,5 @@
> >>>+#
> >>>+# Makefile for the Switch device API
> >>>+#
> >>>+
> >>>+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
> >>>diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
> >>>new file mode 100644
> >>>index 0000000..5010f646
> >>>--- /dev/null
> >>>+++ b/net/switchdev/switchdev.c
> >>>@@ -0,0 +1,33 @@
> >>>+/*
> >>>+ * net/switchdev/switchdev.c - Switch device API
> >>>+ * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
> >>>+ *
> >>>+ * This program is free software; you can redistribute it and/or modify
> >>>+ * it under the terms of the GNU General Public License as published by
> >>>+ * the Free Software Foundation; either version 2 of the License, or
> >>>+ * (at your option) any later version.
> >>>+ */
> >>>+
> >>>+#include <linux/kernel.h>
> >>>+#include <linux/types.h>
> >>>+#include <linux/init.h>
> >>>+#include <linux/netdevice.h>
> >>>+#include <net/switchdev.h>
> >>>+
> >>>+/**
> >>>+ * netdev_sw_parent_id_get - Get ID of a switch
> >>>+ * @dev: port device
> >>>+ * @psid: switch ID
> >>>+ *
> >>>+ * Get ID of a switch this port is part of.
> >>>+ */
> >>>+int netdev_sw_parent_id_get(struct net_device *dev,
> >>>+ struct netdev_phys_item_id *psid)
> >>>+{
> >>>+ const struct net_device_ops *ops = dev->netdev_ops;
> >>>+
> >>>+ if (!ops->ndo_sw_parent_id_get)
> >>>+ return -EOPNOTSUPP;
> >>>+ return ops->ndo_sw_parent_id_get(dev, psid);
> >>>+}
> >>>+EXPORT_SYMBOL(netdev_sw_parent_id_get);
> >--
> >To unsubscribe from this list: send the line "unsubscribe netdev" in
> >the body of a message to majordomo@vger.kernel.org
> >More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] net: team: expose sysfs attributes for each team option
From: Thomas Graf @ 2014-11-20 16:05 UTC (permalink / raw)
To: Hamad Kadmany
Cc: Cong Wang, Hamad Kadmany, Jiri Pirko, netdev, Daniel Borkmann
In-Reply-To: <546CECAD.1040402@redhat.com>
On 11/19/14 at 08:17pm, Daniel Borkmann wrote:
> On 11/19/2014 07:45 PM, Cong Wang wrote:
> >On Wed, Nov 19, 2014 at 4:28 AM, Hamad Kadmany <hkadmany@codeaurora.org> wrote:
> >>On Mon, November 17, 2014 1:02 pm, Jiri Pirko wrote:
> >>>
> >>>Nak.
> >>>
> >>>I don't like this patch. The plan for team was keep things simple and to
> >>>have single userspace api using netlink, as that is the correct way to
> >>>deal with things. Sysfs for this use-case is not. Please, use netlink api.
>
> +1
>
> >>Using team driver requires using libnl3. In Android based platforms, libnl3
> >> is not supported, and libnl3 license poses constraints in Android's user-space.
>
> Constraints?! libnl3 is LGPL ...
The behaviour on this particular topic is disappointing. Instead of
working with the community and using an existing library such as
libmnl or libnl Android chose to fork libnl3 and disregard the
community a couple of years ago.
The reasoning in this thread is the next episode of the same story.
Very disappointing.
^ permalink raw reply
* Re: [PATCH 00/10] net: phy: add device-type abstraction
From: Florian Fainelli @ 2014-11-20 16:18 UTC (permalink / raw)
To: Johan Hovold
Cc: David S. Miller, netdev, linux-kernel, Bruno Thomsen,
Sascha Hauer, Mark Rutland
In-Reply-To: <1416398363-32306-1-git-send-email-johan@kernel.org>
On 11/19/2014 03:59 AM, Johan Hovold wrote:
> This series adds device and device-type abstractions to the micrel
> driver, and enables support for RMII-reference clock selection for
> KSZ8081 and KSZ8091 devices.
>
> While adding support for more features for the Micrel PHYs mentioned
> above, it became apparent that the configuration space is much too large
> and that adding type-specific callbacks will simply not scale. Instead I
> added a driver_data field to struct phy_device, which can be used to
> store static device type data that can be parsed and acted on in
> generic driver callbacks. This allows a lot of duplicated code to be
> removed, and should make it much easier to add new features or deal with
> device-type quirks in the future.
>
> The series has been tested on a dual KSZ8081 setup. Further testing on
> other Micrel PHYs would be much appreciated.
>
> The recent commit a95a18afe4c8 ("phy/micrel: KSZ8031RNL RMII clock
> reconfiguration bug") currently prevents KSZ8031 PHYs from using the
> generic config-init. Bruno, who is the author of that patch, has agreed
> to test this series and some follow-up diagnostic patches to determine
> how best to incorporate these devices as well. I intend to send a
> follow-up patch that removes the custom 8031 config-init and documents
> this quirk, but the current series can be applied meanwhile.
>
> These patches are against net-next which contains some already merged
> prerequisite patches to the driver.
LGTM, thanks Johan!
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
>
> Johan
>
>
> Johan Hovold (10):
> net: phy: add static data field to struct phy_driver
> net: phy: micrel: add device-type abstraction
> net: phy: micrel: parse of nodes at probe
> net: phy: micrel: add has-broadcast-disable flag to type data
> net: phy: micrel: add generic clock-mode-select support
> net: phy: micrel: add support for clock-mode select to KSZ8081/KSZ8091
> dt/bindings: reformat micrel eth-phy documentation
> dt/bindings: add clock-select function property to micrel phy binding
> net: phy: micrel: refactor interrupt config
> net: phy: micrel: add copyright entry
>
> Documentation/devicetree/bindings/net/micrel.txt | 37 ++--
> drivers/net/phy/micrel.c | 262 ++++++++++++++---------
> include/linux/micrel_phy.h | 1 -
> include/linux/phy.h | 2 +
> 4 files changed, 184 insertions(+), 118 deletions(-)
>
^ permalink raw reply
* [PATCH net-next] tcp: remove from tcp_sendmsg() some fastopen code
From: Eric Dumazet @ 2014-11-20 16:23 UTC (permalink / raw)
To: David Miller; +Cc: ycheng, nuclearcat, netdev, ncardwell
In-Reply-To: <1416497628.8629.24.camel@edumazet-glaptop2.roam.corp.google.com>
From: Eric Dumazet <edumazet@google.com>
If we consume iovec bytes in tcp_send_syn_data(), we can remove
annoying fastopen code in tcp_sendmsg() skipping over the already
consumed bytes.
Also add an unlikely(flags & MSG_FASTOPEN), as most TCP sendmsg() do not
ask for FASTOPEN.
Tested:
Ran our 125 packetdrill fastopen tests
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 14 ++------------
net/ipv4/tcp_output.c | 4 ++--
2 files changed, 4 insertions(+), 14 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c239f4740d10b10b67ef4fa44c831851fb9e1dcf..227540eef9d0870721258f9ddbace27b417c619e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1089,20 +1089,19 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags, err, copied = 0;
- int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
+ int mss_now = 0, size_goal, copied_syn = 0;
bool sg;
long timeo;
lock_sock(sk);
flags = msg->msg_flags;
- if (flags & MSG_FASTOPEN) {
+ if (unlikely(flags & MSG_FASTOPEN)) {
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
if (err == -EINPROGRESS && copied_syn > 0)
goto out;
else if (err)
goto out_err;
- offset = copied_syn;
}
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -1151,15 +1150,6 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
unsigned char __user *from = iov->iov_base;
iov++;
- if (unlikely(offset > 0)) { /* Skip bytes copied in SYN */
- if (offset >= seglen) {
- offset -= seglen;
- continue;
- }
- seglen -= offset;
- from += offset;
- offset = 0;
- }
while (seglen > 0) {
int copy = 0;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f5bd4bd3f7e669b3fd48a843d55e7313a30a3409..524e5b657e881a348f11def3f48f29a76f54fbab 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3049,8 +3049,8 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
goto fallback;
syn_data->ip_summed = CHECKSUM_PARTIAL;
memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
- if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space),
- fo->data->msg_iov, 0, space))) {
+ if (unlikely(memcpy_fromiovec(skb_put(syn_data, space),
+ fo->data->msg_iov, space))) {
kfree_skb(syn_data);
goto fallback;
}
^ permalink raw reply related
* Re: [PATCH net-next 1/4] net: allow large number of rx queues
From: Pankaj Gupta @ 2014-11-20 16:31 UTC (permalink / raw)
To: Cong Wang
Cc: linux-kernel, netdev, David Miller, Jason Wang,
Michael S. Tsirkin, dgibson, vfalico, Eric Dumazet,
Vladislav Yasevich, Jerry Chu, wuzhy, Pavel Emelyanov,
Tom Herbert, bhutchings, xii, Stephen Hemminger,
Jiří Pírko, sergei shtylyov
In-Reply-To: <CAHA+R7MnLy=8uL_hSnx=BN2QTs2kvempTxtmSO6hjcS+E0yRwg@mail.gmail.com>
> On Tue, Nov 18, 2014 at 8:22 AM, Pankaj Gupta <pagupta@redhat.com> wrote:
> >
> > As vmalloc() adds overhead on a critical network path,
> > __GFP_REPEAT flag is used with kzalloc() to do this fallback
> > only when really needed.
> >
>
> Are you sure we need __GFP_REPEAT? We have vmalloc() as
> fallback of kmalloc() in many places of networking (grep kvfree),
> none of those I checked has this flag set.
Its there in netif_alloc_netdev_queues() function in same file.
Also, I found it some other places as well.
I think its good to have.
>
^ permalink raw reply
* [PATCH net-next v1 0/8] amd-xgbe: AMD XGBE driver updates 2014-11-20
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
The following series of patches includes functional updates to the
driver as well as some trivial changes.
- Add a read memory barrier in the Tx and Rx path after checking the
descriptor ownership bit
- Wait for the Tx engine to stop/suspend before issuing a stop command
- Implement a smatch tool suggestion to simplify an if statement
- Separate out Tx and Rx ring data fields into their own structures
- Add BQL support
- Remove an unused variable
- Change Tx coalescing support to operate on packet basis instead of
a descriptor basis
- Add support for the skb->xmit_more flag
This patch series is based on net-next.
---
Tom Lendacky (8):
amd-xgbe: Add a read memory barrier to Tx/Rx path
amd-xgbe: Tx engine must not be active before stopping it
amd-xgbe: Incorporate Smatch coding suggestion
amd-xgbe: Separate Tx/Rx ring data fields into new structs
amd-xgbe: Add BQL support
amd-xgbe: Remove unused variable
amd-xgbe: Perform Tx coalescing on a packet basis
amd-xgbe: Add support for the skb->xmit_more flag
drivers/net/ethernet/amd/xgbe/xgbe-common.h | 21 ++-
drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 40 +++---
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 170 +++++++++++++++++++++------
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 112 ++++++++++++++----
drivers/net/ethernet/amd/xgbe/xgbe.h | 42 ++++++-
5 files changed, 289 insertions(+), 96 deletions(-)
--
Tom Lendacky
^ permalink raw reply
* [PATCH net-next v1 1/8] amd-xgbe: Add a read memory barrier to Tx/Rx path
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
Add a read memory barrier to the Tx and Rx paths where the ownership
bit is checked to be sure that all descriptor fields are read after
having read the ownership bit for the descriptor.
This has not been an issue to date, but it's a good safe-guard to have.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 3 +++
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index f6014d3..9b1d9fa 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1558,6 +1558,9 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN))
return 1;
+ /* Make sure descriptor fields are read after reading the OWN bit */
+ rmb();
+
#ifdef XGMAC_ENABLE_RX_DESC_DUMP
xgbe_dump_rx_desc(ring, rdesc, ring->cur);
#endif
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 0544931..eebb787 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1791,6 +1791,10 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
if (!hw_if->tx_complete(rdesc))
break;
+ /* Make sure descriptor fields are read after reading the OWN
+ * bit */
+ rmb();
+
#ifdef XGMAC_ENABLE_TX_DESC_DUMP
xgbe_dump_tx_desc(ring, ring->dirty, 1, 0);
#endif
^ permalink raw reply related
* [PATCH net-next v1 2/8] amd-xgbe: Tx engine must not be active before stopping it
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
If the Tx engine is told to stop while it is actively processing Tx
descriptors it is possible that the Tx descriptor(s) will not be closed
out properly. When the Tx engine is restarted this could result in the
driver being stuck on the improperly closed descriptor.
Update the driver to wait for the Tx engine to be in a stopped or
suspended state before issuing the stop command.
This has not been an issue to date, but it's a good safe-guard to have.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-common.h | 21 ++++++----
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 59 +++++++++++++++++++++++++++
drivers/net/ethernet/amd/xgbe/xgbe.h | 1
3 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 2fe8fc7..75b08c6 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -125,9 +125,6 @@
#define DMA_AXIAWCR 0x3018
#define DMA_DSR0 0x3020
#define DMA_DSR1 0x3024
-#define DMA_DSR2 0x3028
-#define DMA_DSR3 0x302c
-#define DMA_DSR4 0x3030
/* DMA register entry bit positions and sizes */
#define DMA_AXIARCR_DRC_INDEX 0
@@ -158,10 +155,6 @@
#define DMA_AXIAWCR_TDC_WIDTH 4
#define DMA_AXIAWCR_TDD_INDEX 28
#define DMA_AXIAWCR_TDD_WIDTH 2
-#define DMA_DSR0_RPS_INDEX 8
-#define DMA_DSR0_RPS_WIDTH 4
-#define DMA_DSR0_TPS_INDEX 12
-#define DMA_DSR0_TPS_WIDTH 4
#define DMA_ISR_MACIS_INDEX 17
#define DMA_ISR_MACIS_WIDTH 1
#define DMA_ISR_MTLIS_INDEX 16
@@ -175,6 +168,20 @@
#define DMA_SBMR_UNDEF_INDEX 0
#define DMA_SBMR_UNDEF_WIDTH 1
+/* DMA register values */
+#define DMA_DSR_RPS_WIDTH 4
+#define DMA_DSR_TPS_WIDTH 4
+#define DMA_DSR_Q_WIDTH (DMA_DSR_RPS_WIDTH + DMA_DSR_TPS_WIDTH)
+#define DMA_DSR0_RPS_START 8
+#define DMA_DSR0_TPS_START 12
+#define DMA_DSRX_FIRST_QUEUE 3
+#define DMA_DSRX_INC 4
+#define DMA_DSRX_QPR 4
+#define DMA_DSRX_RPS_START 0
+#define DMA_DSRX_TPS_START 4
+#define DMA_TPS_STOPPED 0x00
+#define DMA_TPS_SUSPENDED 0x06
+
/* DMA channel register offsets
* Multiple channels can be active. The first channel has registers
* that begin at 0x3100. Each subsequent channel has registers that
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 9b1d9fa..dcd0347 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -2453,6 +2453,47 @@ static void xgbe_config_mmc(struct xgbe_prv_data *pdata)
XGMAC_IOWRITE_BITS(pdata, MMC_CR, CR, 1);
}
+static void xgbe_prepare_tx_stop(struct xgbe_prv_data *pdata,
+ struct xgbe_channel *channel)
+{
+ unsigned int tx_dsr, tx_pos, tx_qidx;
+ unsigned int tx_status;
+ unsigned long tx_timeout;
+
+ /* Calculate the status register to read and the position within */
+ if (channel->queue_index < DMA_DSRX_FIRST_QUEUE) {
+ tx_dsr = DMA_DSR0;
+ tx_pos = (channel->queue_index * DMA_DSR_Q_WIDTH) +
+ DMA_DSR0_TPS_START;
+ } else {
+ tx_qidx = channel->queue_index - DMA_DSRX_FIRST_QUEUE;
+
+ tx_dsr = DMA_DSR1 + ((tx_qidx / DMA_DSRX_QPR) * DMA_DSRX_INC);
+ tx_pos = ((tx_qidx % DMA_DSRX_QPR) * DMA_DSR_Q_WIDTH) +
+ DMA_DSRX_TPS_START;
+ }
+
+ /* The Tx engine cannot be stopped if it is actively processing
+ * descriptors. Wait for the Tx engine to enter the stopped or
+ * suspended state. Don't wait forever though...
+ */
+ tx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
+ while (time_before(jiffies, tx_timeout)) {
+ tx_status = XGMAC_IOREAD(pdata, tx_dsr);
+ tx_status = GET_BITS(tx_status, tx_pos, DMA_DSR_TPS_WIDTH);
+ if ((tx_status == DMA_TPS_STOPPED) ||
+ (tx_status == DMA_TPS_SUSPENDED))
+ break;
+
+ usleep_range(500, 1000);
+ }
+
+ if (!time_before(jiffies, tx_timeout))
+ netdev_info(pdata->netdev,
+ "timed out waiting for Tx DMA channel %u to stop\n",
+ channel->queue_index);
+}
+
static void xgbe_enable_tx(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
@@ -2481,6 +2522,15 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata)
struct xgbe_channel *channel;
unsigned int i;
+ /* Prepare for Tx DMA channel stop */
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (!channel->tx_ring)
+ break;
+
+ xgbe_prepare_tx_stop(pdata, channel);
+ }
+
/* Disable MAC Tx */
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
@@ -2572,6 +2622,15 @@ static void xgbe_powerdown_tx(struct xgbe_prv_data *pdata)
struct xgbe_channel *channel;
unsigned int i;
+ /* Prepare for Tx DMA channel stop */
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (!channel->tx_ring)
+ break;
+
+ xgbe_prepare_tx_stop(pdata, channel);
+ }
+
/* Disable MAC Tx */
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 901fb1f..46ce544 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -147,6 +147,7 @@
#define XGBE_MAX_DMA_CHANNELS 16
#define XGBE_MAX_QUEUES 16
+#define XGBE_DMA_STOP_TIMEOUT 5
/* DMA cache settings - Outer sharable, write-back, write-allocate */
#define XGBE_DMA_OS_AXDOMAIN 0x2
^ permalink raw reply related
* [PATCH net-next v1 3/8] amd-xgbe: Incorporate Smatch coding suggestion
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Dan Carpenter
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
The Smatch tool indicated that one of the if statements in xgbe-dev.c
could be rewritten to remove a redundant check for the 'err' variable
in an if statement.
Change the statement as suggested and add a comment to help clarify.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index dcd0347..72425ff 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1633,7 +1633,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
etlt = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ETLT);
DBGPR(" err=%u, etlt=%#x\n", err, etlt);
- if (!err || (err && !etlt)) {
+ if (!err || !etlt) {
+ /* No error if err is 0 or etlt is 0 */
if ((etlt == 0x09) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
^ permalink raw reply related
* [PATCH net-next v1 4/8] amd-xgbe: Separate Tx/Rx ring data fields into new structs
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
Move the Tx and Rx related fields within the xgbe_ring_data struct into
their own structs in order to more easily see what fields are used for
each operation.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 36 ++++++++++++++---------------
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 14 ++++++-----
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 28 +++++++++++------------
drivers/net/ethernet/amd/xgbe/xgbe.h | 22 +++++++++++++-----
4 files changed, 54 insertions(+), 46 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index e6b9f54..3c7c386 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -335,11 +335,11 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata,
}
/* Set up the header page info */
- xgbe_set_buffer_data(&rdata->rx_hdr, &ring->rx_hdr_pa,
+ xgbe_set_buffer_data(&rdata->rx.hdr, &ring->rx_hdr_pa,
XGBE_SKB_ALLOC_SIZE);
/* Set up the buffer page info */
- xgbe_set_buffer_data(&rdata->rx_buf, &ring->rx_buf_pa,
+ xgbe_set_buffer_data(&rdata->rx.buf, &ring->rx_buf_pa,
pdata->rx_buf_size);
return 0;
@@ -451,31 +451,29 @@ static void xgbe_unmap_rdata(struct xgbe_prv_data *pdata,
rdata->skb = NULL;
}
- if (rdata->rx_hdr.pa.pages)
- put_page(rdata->rx_hdr.pa.pages);
+ if (rdata->rx.hdr.pa.pages)
+ put_page(rdata->rx.hdr.pa.pages);
- if (rdata->rx_hdr.pa_unmap.pages) {
- dma_unmap_page(pdata->dev, rdata->rx_hdr.pa_unmap.pages_dma,
- rdata->rx_hdr.pa_unmap.pages_len,
+ if (rdata->rx.hdr.pa_unmap.pages) {
+ dma_unmap_page(pdata->dev, rdata->rx.hdr.pa_unmap.pages_dma,
+ rdata->rx.hdr.pa_unmap.pages_len,
DMA_FROM_DEVICE);
- put_page(rdata->rx_hdr.pa_unmap.pages);
+ put_page(rdata->rx.hdr.pa_unmap.pages);
}
- if (rdata->rx_buf.pa.pages)
- put_page(rdata->rx_buf.pa.pages);
+ if (rdata->rx.buf.pa.pages)
+ put_page(rdata->rx.buf.pa.pages);
- if (rdata->rx_buf.pa_unmap.pages) {
- dma_unmap_page(pdata->dev, rdata->rx_buf.pa_unmap.pages_dma,
- rdata->rx_buf.pa_unmap.pages_len,
+ if (rdata->rx.buf.pa_unmap.pages) {
+ dma_unmap_page(pdata->dev, rdata->rx.buf.pa_unmap.pages_dma,
+ rdata->rx.buf.pa_unmap.pages_len,
DMA_FROM_DEVICE);
- put_page(rdata->rx_buf.pa_unmap.pages);
+ put_page(rdata->rx.buf.pa_unmap.pages);
}
- memset(&rdata->rx_hdr, 0, sizeof(rdata->rx_hdr));
- memset(&rdata->rx_buf, 0, sizeof(rdata->rx_buf));
+ memset(&rdata->tx, 0, sizeof(rdata->tx));
+ memset(&rdata->rx, 0, sizeof(rdata->rx));
- rdata->tso_header = 0;
- rdata->len = 0;
rdata->interrupt = 0;
rdata->mapped_as_page = 0;
@@ -534,7 +532,7 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
}
rdata->skb_dma = skb_dma;
rdata->skb_dma_len = packet->header_len;
- rdata->tso_header = 1;
+ rdata->tx.tso_header = 1;
offset = packet->header_len;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 72425ff..2908ad1 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1085,10 +1085,10 @@ static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata)
* Set buffer 2 (hi) address to buffer dma address (hi) and
* set control bits OWN and INTE
*/
- rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx_hdr.dma));
- rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx_hdr.dma));
- rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx_buf.dma));
- rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx_buf.dma));
+ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx.hdr.dma));
+ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx.hdr.dma));
+ rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma));
+ rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma));
XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE,
rdata->interrupt ? 1 : 0);
@@ -1586,8 +1586,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
/* Get the header length */
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD))
- rdata->hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
- RX_NORMAL_DESC2, HL);
+ rdata->rx.hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
+ RX_NORMAL_DESC2, HL);
/* Get the RSS hash */
if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, RSV)) {
@@ -1610,7 +1610,7 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
}
/* Get the packet length */
- rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
+ rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) {
/* Not all the data has been transferred for this packet */
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index eebb787..46ea423 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1747,14 +1747,14 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata,
u8 *packet;
unsigned int copy_len;
- skb = netdev_alloc_skb_ip_align(netdev, rdata->rx_hdr.dma_len);
+ skb = netdev_alloc_skb_ip_align(netdev, rdata->rx.hdr.dma_len);
if (!skb)
return NULL;
- packet = page_address(rdata->rx_hdr.pa.pages) +
- rdata->rx_hdr.pa.pages_offset;
- copy_len = (rdata->hdr_len) ? rdata->hdr_len : *len;
- copy_len = min(rdata->rx_hdr.dma_len, copy_len);
+ packet = page_address(rdata->rx.hdr.pa.pages) +
+ rdata->rx.hdr.pa.pages_offset;
+ copy_len = (rdata->rx.hdr_len) ? rdata->rx.hdr_len : *len;
+ copy_len = min(rdata->rx.hdr.dma_len, copy_len);
skb_copy_to_linear_data(skb, packet, copy_len);
skb_put(skb, copy_len);
@@ -1900,13 +1900,13 @@ read_again:
}
if (!context) {
- put_len = rdata->len - len;
+ put_len = rdata->rx.len - len;
len += put_len;
if (!skb) {
dma_sync_single_for_cpu(pdata->dev,
- rdata->rx_hdr.dma,
- rdata->rx_hdr.dma_len,
+ rdata->rx.hdr.dma,
+ rdata->rx.hdr.dma_len,
DMA_FROM_DEVICE);
skb = xgbe_create_skb(pdata, rdata, &put_len);
@@ -1918,15 +1918,15 @@ read_again:
if (put_len) {
dma_sync_single_for_cpu(pdata->dev,
- rdata->rx_buf.dma,
- rdata->rx_buf.dma_len,
+ rdata->rx.buf.dma,
+ rdata->rx.buf.dma_len,
DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
- rdata->rx_buf.pa.pages,
- rdata->rx_buf.pa.pages_offset,
- put_len, rdata->rx_buf.dma_len);
- rdata->rx_buf.pa.pages = NULL;
+ rdata->rx.buf.pa.pages,
+ rdata->rx.buf.pa.pages_offset,
+ put_len, rdata->rx.buf.dma_len);
+ rdata->rx.buf.pa.pages = NULL;
}
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 46ce544..41ce6e3 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -271,6 +271,20 @@ struct xgbe_buffer_data {
unsigned int dma_len;
};
+/* Tx-related ring data */
+struct xgbe_tx_ring_data {
+ unsigned int tso_header; /* TSO header indicator */
+};
+
+/* Rx-related ring data */
+struct xgbe_rx_ring_data {
+ struct xgbe_buffer_data hdr; /* Header locations */
+ struct xgbe_buffer_data buf; /* Payload locations */
+
+ unsigned short hdr_len; /* Length of received header */
+ unsigned short len; /* Length of received packet */
+};
+
/* Structure used to hold information related to the descriptor
* and the packet associated with the descriptor (always use
* use the XGBE_GET_DESC_DATA macro to access this data from the ring)
@@ -282,13 +296,9 @@ struct xgbe_ring_data {
struct sk_buff *skb; /* Virtual address of SKB */
dma_addr_t skb_dma; /* DMA address of SKB data */
unsigned int skb_dma_len; /* Length of SKB DMA area */
- unsigned int tso_header; /* TSO header indicator */
- struct xgbe_buffer_data rx_hdr; /* Header locations */
- struct xgbe_buffer_data rx_buf; /* Payload locations */
-
- unsigned short hdr_len; /* Length of received header */
- unsigned short len; /* Length of received Rx packet */
+ struct xgbe_tx_ring_data tx; /* Tx-related data */
+ struct xgbe_rx_ring_data rx; /* Rx-related data */
unsigned int interrupt; /* Interrupt indicator */
^ permalink raw reply related
* [PATCH net-next v1 5/8] amd-xgbe: Add BQL support
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
Call the appropriate BQL functions to track the number of bytes queued
during Tx processing and to track the number of packets and bytes
that have been transmitted during Tx complete processing.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 +++
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 43 +++++++++++++++++++++++++++++-
drivers/net/ethernet/amd/xgbe/xgbe.h | 5 +++
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 2908ad1..78db5a6 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1500,6 +1500,10 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
/* Set LAST bit for the last descriptor */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD, 1);
+ /* Save the Tx info to report back during cleanup */
+ rdata->tx.packets = packet->tx_packets;
+ rdata->tx.bytes = packet->tx_bytes;
+
/* In case the Tx DMA engine is running, make sure everything
* is written to the descriptor(s) before setting the OWN bit
* for the first descriptor
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 46ea423..f963528 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -876,7 +876,10 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
static void xgbe_stop(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
+ struct xgbe_channel *channel;
struct net_device *netdev = pdata->netdev;
+ struct netdev_queue *txq;
+ unsigned int i;
DBGPR("-->xgbe_stop\n");
@@ -890,6 +893,15 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
hw_if->disable_tx(pdata);
hw_if->disable_rx(pdata);
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (!channel->tx_ring)
+ continue;
+
+ txq = netdev_get_tx_queue(netdev, channel->queue_index);
+ netdev_tx_reset_queue(txq);
+ }
+
DBGPR("<--xgbe_stop\n");
}
@@ -1156,6 +1168,12 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet)
packet->tcp_header_len, packet->tcp_payload_len);
DBGPR(" packet->mss=%u\n", packet->mss);
+ /* Update the number of packets that will ultimately be transmitted
+ * along with the extra bytes for each extra packet
+ */
+ packet->tx_packets = skb_shinfo(skb)->gso_segs;
+ packet->tx_bytes += (packet->tx_packets - 1) * packet->header_len;
+
return 0;
}
@@ -1184,6 +1202,9 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
context_desc = 0;
packet->rdesc_count = 0;
+ packet->tx_packets = 1;
+ packet->tx_bytes = skb->len;
+
if (xgbe_is_tso(skb)) {
/* TSO requires an extra descriptor if mss is different */
if (skb_shinfo(skb)->gso_size != ring->tx.cur_mss) {
@@ -1400,12 +1421,14 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
struct xgbe_channel *channel;
struct xgbe_ring *ring;
struct xgbe_packet_data *packet;
+ struct netdev_queue *txq;
unsigned long flags;
int ret;
DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len);
channel = pdata->channel + skb->queue_mapping;
+ txq = netdev_get_tx_queue(netdev, channel->queue_index);
ring = channel->tx_ring;
packet = &ring->packet_data;
@@ -1447,6 +1470,9 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
xgbe_prep_tx_tstamp(pdata, skb, packet);
+ /* Report on the actual number of bytes (to be) sent */
+ netdev_tx_sent_queue(txq, packet->tx_bytes);
+
/* Configure required descriptor fields for transmission */
hw_if->dev_xmit(channel);
@@ -1772,8 +1798,10 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
struct xgbe_ring_data *rdata;
struct xgbe_ring_desc *rdesc;
struct net_device *netdev = pdata->netdev;
+ struct netdev_queue *txq;
unsigned long flags;
int processed = 0;
+ unsigned int tx_packets = 0, tx_bytes = 0;
DBGPR("-->xgbe_tx_poll\n");
@@ -1781,6 +1809,8 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
if (!ring)
return 0;
+ txq = netdev_get_tx_queue(netdev, channel->queue_index);
+
spin_lock_irqsave(&ring->lock, flags);
while ((processed < XGBE_TX_DESC_MAX_PROC) &&
@@ -1799,6 +1829,11 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
xgbe_dump_tx_desc(ring, ring->dirty, 1, 0);
#endif
+ if (hw_if->is_last_desc(rdesc)) {
+ tx_packets += rdata->tx.packets;
+ tx_bytes += rdata->tx.bytes;
+ }
+
/* Free the SKB and reset the descriptor for re-use */
desc_if->unmap_rdata(pdata, rdata);
hw_if->tx_desc_reset(rdata);
@@ -1807,14 +1842,20 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
ring->dirty++;
}
+ if (!processed)
+ goto unlock;
+
+ netdev_tx_completed_queue(txq, tx_packets, tx_bytes);
+
if ((ring->tx.queue_stopped == 1) &&
(xgbe_tx_avail_desc(ring) > XGBE_TX_DESC_MIN_FREE)) {
ring->tx.queue_stopped = 0;
- netif_wake_subqueue(netdev, channel->queue_index);
+ netif_tx_wake_queue(txq);
}
DBGPR("<--xgbe_tx_poll: processed=%d\n", processed);
+unlock:
spin_unlock_irqrestore(&ring->lock, flags);
return processed;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 41ce6e3..98504f1 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -243,6 +243,9 @@ struct xgbe_packet_data {
u32 rss_hash;
enum pkt_hash_types rss_hash_type;
+
+ unsigned int tx_packets;
+ unsigned int tx_bytes;
};
/* Common Rx and Tx descriptor mapping */
@@ -274,6 +277,8 @@ struct xgbe_buffer_data {
/* Tx-related ring data */
struct xgbe_tx_ring_data {
unsigned int tso_header; /* TSO header indicator */
+ unsigned int packets; /* BQL packet count */
+ unsigned int bytes; /* BQL byte count */
};
/* Rx-related ring data */
^ permalink raw reply related
* [PATCH net-next v1 6/8] amd-xgbe: Remove unused variable
From: Tom Lendacky @ 2014-11-20 17:03 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
The tso_header variable in the xgbe_tx_ring_data structure is not used,
remove it.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 1 -
drivers/net/ethernet/amd/xgbe/xgbe.h | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index 3c7c386..62cb4d3 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -532,7 +532,6 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb)
}
rdata->skb_dma = skb_dma;
rdata->skb_dma_len = packet->header_len;
- rdata->tx.tso_header = 1;
offset = packet->header_len;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 98504f1..ec0d37a 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -276,7 +276,6 @@ struct xgbe_buffer_data {
/* Tx-related ring data */
struct xgbe_tx_ring_data {
- unsigned int tso_header; /* TSO header indicator */
unsigned int packets; /* BQL packet count */
unsigned int bytes; /* BQL byte count */
};
^ permalink raw reply related
* [PATCH net-next v1 7/8] amd-xgbe: Perform Tx coalescing on a packet basis
From: Tom Lendacky @ 2014-11-20 17:04 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
The current form of Tx coalescing works on a descriptor basis instead
of on a packet basis and doesn't take into account TSO packets. Update
the Tx coalescing support to work on a packet basis, taking into
account the number of packets associated with a TSO transmit. Also,
only activate the Tx timer if a timer value is set.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 46 +++++++++++++++++-------------
1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 78db5a6..b3d2433 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1334,7 +1334,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
struct xgbe_packet_data *packet = &ring->packet_data;
unsigned int csum, tso, vlan;
unsigned int tso_context, vlan_context;
- unsigned int tx_coalesce, tx_frames;
+ unsigned int tx_set_ic;
int start_index = ring->cur;
int i;
@@ -1357,10 +1357,26 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
else
vlan_context = 0;
- tx_coalesce = (pdata->tx_usecs || pdata->tx_frames) ? 1 : 0;
- tx_frames = pdata->tx_frames;
- if (tx_coalesce && !channel->tx_timer_active)
- ring->coalesce_count = 0;
+ /* Determine if an interrupt should be generated for this Tx:
+ * Interrupt:
+ * - Tx frame count exceeds the frame count setting
+ * - Addition of Tx frame count to the frame count since the
+ * last interrupt was set exceeds the frame count setting
+ * No interrupt:
+ * - No frame count setting specified (ethtool -C ethX tx-frames 0)
+ * - Addition of Tx frame count to the frame count since the
+ * last interrupt was set does not exceed the frame count setting
+ */
+ ring->coalesce_count += packet->tx_packets;
+ if (!pdata->tx_frames)
+ tx_set_ic = 0;
+ else if (packet->tx_packets > pdata->tx_frames)
+ tx_set_ic = 1;
+ else if ((ring->coalesce_count % pdata->tx_frames) <
+ packet->tx_packets)
+ tx_set_ic = 1;
+ else
+ tx_set_ic = 0;
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
rdesc = rdata->rdesc;
@@ -1427,13 +1443,6 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP))
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, TTSE, 1);
- /* Set IC bit based on Tx coalescing settings */
- XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
- if (tx_coalesce && (!tx_frames ||
- (++ring->coalesce_count % tx_frames)))
- /* Clear IC bit */
- XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 0);
-
/* Mark it as First Descriptor */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, FD, 1);
@@ -1478,13 +1487,6 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, HL_B1L,
rdata->skb_dma_len);
- /* Set IC bit based on Tx coalescing settings */
- XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
- if (tx_coalesce && (!tx_frames ||
- (++ring->coalesce_count % tx_frames)))
- /* Clear IC bit */
- XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 0);
-
/* Set OWN bit */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
@@ -1500,6 +1502,10 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
/* Set LAST bit for the last descriptor */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD, 1);
+ /* Set IC bit based on Tx coalescing settings */
+ if (tx_set_ic)
+ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
+
/* Save the Tx info to report back during cleanup */
rdata->tx.packets = packet->tx_packets;
rdata->tx.bytes = packet->tx_bytes;
@@ -1530,7 +1536,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
lower_32_bits(rdata->rdesc_dma));
/* Start the Tx coalescing timer */
- if (tx_coalesce && !channel->tx_timer_active) {
+ if (pdata->tx_usecs && !channel->tx_timer_active) {
channel->tx_timer_active = 1;
hrtimer_start(&channel->tx_timer,
ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC),
^ permalink raw reply related
* [PATCH net-next v1 8/8] amd-xgbe: Add support for the skb->xmit_more flag
From: Tom Lendacky @ 2014-11-20 17:04 UTC (permalink / raw)
To: netdev; +Cc: David Miller
In-Reply-To: <20141120170320.15397.10583.stgit@tlendack-t1.amdoffice.net>
Add support to delay telling the hardware about data that is ready to
be transmitted if the skb->xmit_more flag is set.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 5 +--
drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 43 ++++++++++++++++++++---------
drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 37 +++++++++++++++++++++----
drivers/net/ethernet/amd/xgbe/xgbe.h | 15 ++++++++++
4 files changed, 78 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index 62cb4d3..51b68d1 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -378,7 +378,7 @@ static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata)
ring->cur = 0;
ring->dirty = 0;
- ring->tx.queue_stopped = 0;
+ memset(&ring->tx, 0, sizeof(ring->tx));
hw_if->tx_desc_init(channel);
}
@@ -422,8 +422,7 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata)
ring->cur = 0;
ring->dirty = 0;
- ring->rx.realloc_index = 0;
- ring->rx.realloc_threshold = 0;
+ memset(&ring->rx, 0, sizeof(ring->rx));
hw_if->rx_desc_init(channel);
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index b3d2433..53f5f66 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1325,6 +1325,29 @@ static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
xgbe_config_flow_control(pdata);
}
+static void xgbe_tx_start_xmit(struct xgbe_channel *channel,
+ struct xgbe_ring *ring)
+{
+ struct xgbe_prv_data *pdata = channel->pdata;
+ struct xgbe_ring_data *rdata;
+
+ /* Issue a poll command to Tx DMA by writing address
+ * of next immediate free descriptor */
+ rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+ XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO,
+ lower_32_bits(rdata->rdesc_dma));
+
+ /* Start the Tx coalescing timer */
+ if (pdata->tx_usecs && !channel->tx_timer_active) {
+ channel->tx_timer_active = 1;
+ hrtimer_start(&channel->tx_timer,
+ ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC),
+ HRTIMER_MODE_REL);
+ }
+
+ ring->tx.xmit_more = 0;
+}
+
static void xgbe_dev_xmit(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
@@ -1528,20 +1551,13 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
/* Make sure ownership is written to the descriptor */
wmb();
- /* Issue a poll command to Tx DMA by writing address
- * of next immediate free descriptor */
ring->cur++;
- rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
- XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO,
- lower_32_bits(rdata->rdesc_dma));
-
- /* Start the Tx coalescing timer */
- if (pdata->tx_usecs && !channel->tx_timer_active) {
- channel->tx_timer_active = 1;
- hrtimer_start(&channel->tx_timer,
- ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC),
- HRTIMER_MODE_REL);
- }
+ if (!packet->skb->xmit_more ||
+ netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev,
+ channel->queue_index)))
+ xgbe_tx_start_xmit(channel, ring);
+ else
+ ring->tx.xmit_more = 1;
DBGPR(" %s: descriptors %u to %u written\n",
channel->name, start_index & (ring->rdesc_count - 1),
@@ -2802,6 +2818,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
hw_if->rx_desc_reset = xgbe_rx_desc_reset;
hw_if->is_last_desc = xgbe_is_last_desc;
hw_if->is_context_desc = xgbe_is_context_desc;
+ hw_if->tx_start_xmit = xgbe_tx_start_xmit;
/* For FLOW ctrl */
hw_if->config_tx_flow_control = xgbe_config_tx_flow_control;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index f963528..02c104d 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -225,6 +225,28 @@ static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring)
return (ring->rdesc_count - (ring->cur - ring->dirty));
}
+static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel,
+ struct xgbe_ring *ring, unsigned int count)
+{
+ struct xgbe_prv_data *pdata = channel->pdata;
+
+ if (count > xgbe_tx_avail_desc(ring)) {
+ DBGPR(" Tx queue stopped, not enough descriptors available\n");
+ netif_stop_subqueue(pdata->netdev, channel->queue_index);
+ ring->tx.queue_stopped = 1;
+
+ /* If we haven't notified the hardware because of xmit_more
+ * support, tell it now
+ */
+ if (ring->tx.xmit_more)
+ pdata->hw_if.tx_start_xmit(channel, ring);
+
+ return NETDEV_TX_BUSY;
+ }
+
+ return 0;
+}
+
static int xgbe_calc_rx_buf_size(struct net_device *netdev, unsigned int mtu)
{
unsigned int rx_buf_size;
@@ -1199,6 +1221,8 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
unsigned int len;
unsigned int i;
+ packet->skb = skb;
+
context_desc = 0;
packet->rdesc_count = 0;
@@ -1447,13 +1471,9 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
xgbe_packet_info(pdata, ring, skb, packet);
/* Check that there are enough descriptors available */
- if (packet->rdesc_count > xgbe_tx_avail_desc(ring)) {
- DBGPR(" Tx queue stopped, not enough descriptors available\n");
- netif_stop_subqueue(netdev, channel->queue_index);
- ring->tx.queue_stopped = 1;
- ret = NETDEV_TX_BUSY;
+ ret = xgbe_maybe_stop_tx_queue(channel, ring, packet->rdesc_count);
+ if (ret)
goto tx_netdev_return;
- }
ret = xgbe_prep_tso(skb, packet);
if (ret) {
@@ -1480,6 +1500,11 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
xgbe_print_pkt(netdev, skb, true);
#endif
+ /* Stop the queue in advance if there may not be enough descriptors */
+ xgbe_maybe_stop_tx_queue(channel, ring, XGBE_TX_MAX_DESCS);
+
+ ret = NETDEV_TX_OK;
+
tx_netdev_return:
spin_unlock_irqrestore(&ring->lock, flags);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index ec0d37a..eb33873 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -140,6 +140,17 @@
#define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1))
+/* Descriptors required for maximum contigous TSO/GSO packet */
+#define XGBE_TX_MAX_SPLIT ((GSO_MAX_SIZE / XGBE_TX_MAX_BUF_SIZE) + 1)
+
+/* Maximum possible descriptors needed for an SKB:
+ * - Maximum number of SKB frags
+ * - Maximum descriptors for contiguous TSO/GSO packet
+ * - Possible context descriptor
+ * - Possible TSO header descriptor
+ */
+#define XGBE_TX_MAX_DESCS (MAX_SKB_FRAGS + XGBE_TX_MAX_SPLIT + 2)
+
#define XGBE_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
#define XGBE_RX_BUF_ALIGN 64
#define XGBE_SKB_ALLOC_SIZE 256
@@ -225,6 +236,8 @@
struct xgbe_prv_data;
struct xgbe_packet_data {
+ struct sk_buff *skb;
+
unsigned int attributes;
unsigned int errors;
@@ -360,6 +373,7 @@ struct xgbe_ring {
union {
struct {
unsigned int queue_stopped;
+ unsigned int xmit_more;
unsigned short cur_mss;
unsigned short cur_vlan_ctag;
} tx;
@@ -523,6 +537,7 @@ struct xgbe_hw_if {
void (*tx_desc_reset)(struct xgbe_ring_data *);
int (*is_last_desc)(struct xgbe_ring_desc *);
int (*is_context_desc)(struct xgbe_ring_desc *);
+ void (*tx_start_xmit)(struct xgbe_channel *, struct xgbe_ring *);
/* For FLOW ctrl */
int (*config_tx_flow_control)(struct xgbe_prv_data *);
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox