aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-10-06 01:04:21 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-06 01:04:21 -0400
commit4e62ccd901062c532673f4fda16c484de2c3c8fc (patch)
tree33befd15a97dcb8bb8b3a78bc6d355caf2d37f59
parentf2600cf02b5b59aaee082c3485b7f01fc7f7b70c (diff)
parent1556b8746e52501fdfaadd65837baaa63a9fa937 (diff)
Merge branch 'mlx4-next'
Amir Vadai says: ==================== net/mlx4_en: Optimizations to TX flow This patchset contains optimizations to TX flow in mlx4_en driver. It also introduce setting/getting tx copybreak, to enable controlling inline threshold dynamically. TX flow optimizations was authored and posted to the mailing list by Eric Dumazet [1] as a single patch. I splitted this patch to smaller patches, Reviewed it and tested. Changed from original patch: - s/iowrite32be/iowrite32/, since ring->doorbell_qpn is stored as be32 The tx copybreak patch was also suggested by Eric Dumazet, and was edited and reviewed by me. User space patch will be sent after kernel code is ready. I am sending this patchset now since the merge window is near and don't want to miss it. More work need to do: - Disable BF when xmit_more is in use - Make TSO use xmit_more too. Maybe by splitting small TSO packets in the driver itself, to avoid extra cpu/memory costs of GSO before the driver - Fix mlx4_en_xmit buggy handling of queue full in the middle of a burst partially posted to send queue using xmit_more Eric, I edited the patches to have you as the Author and the first signed-off-by. I hope it is ok with you (I wasn't sure if it is ok to sign by you), anyway all the credit to those changes should go to you. Patchset was tested and applied over commit 1e203c1 "(net: sched: suspicious RCU usage in qdisc_watchdog") [1] - https://patchwork.ozlabs.org/patch/394256/ ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c44
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c330
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h90
-rw-r--r--include/linux/mlx4/device.h2
-rw-r--r--include/uapi/linux/ethtool.h1
-rw-r--r--net/core/ethtool.c1
6 files changed, 290 insertions, 178 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 42c9f8b09a6e..ae83da9cd18a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1267,6 +1267,48 @@ static u32 mlx4_en_get_priv_flags(struct net_device *dev)
1267 return priv->pflags; 1267 return priv->pflags;
1268} 1268}
1269 1269
1270static int mlx4_en_get_tunable(struct net_device *dev,
1271 const struct ethtool_tunable *tuna,
1272 void *data)
1273{
1274 const struct mlx4_en_priv *priv = netdev_priv(dev);
1275 int ret = 0;
1276
1277 switch (tuna->id) {
1278 case ETHTOOL_TX_COPYBREAK:
1279 *(u32 *)data = priv->prof->inline_thold;
1280 break;
1281 default:
1282 ret = -EINVAL;
1283 break;
1284 }
1285
1286 return ret;
1287}
1288
1289static int mlx4_en_set_tunable(struct net_device *dev,
1290 const struct ethtool_tunable *tuna,
1291 const void *data)
1292{
1293 struct mlx4_en_priv *priv = netdev_priv(dev);
1294 int val, ret = 0;
1295
1296 switch (tuna->id) {
1297 case ETHTOOL_TX_COPYBREAK:
1298 val = *(u32 *)data;
1299 if (val < MIN_PKT_LEN || val > MAX_INLINE)
1300 ret = -EINVAL;
1301 else
1302 priv->prof->inline_thold = val;
1303 break;
1304 default:
1305 ret = -EINVAL;
1306 break;
1307 }
1308
1309 return ret;
1310}
1311
1270 1312
1271const struct ethtool_ops mlx4_en_ethtool_ops = { 1313const struct ethtool_ops mlx4_en_ethtool_ops = {
1272 .get_drvinfo = mlx4_en_get_drvinfo, 1314 .get_drvinfo = mlx4_en_get_drvinfo,
@@ -1297,6 +1339,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
1297 .get_ts_info = mlx4_en_get_ts_info, 1339 .get_ts_info = mlx4_en_get_ts_info,
1298 .set_priv_flags = mlx4_en_set_priv_flags, 1340 .set_priv_flags = mlx4_en_set_priv_flags,
1299 .get_priv_flags = mlx4_en_get_priv_flags, 1341 .get_priv_flags = mlx4_en_get_priv_flags,
1342 .get_tunable = mlx4_en_get_tunable,
1343 .set_tunable = mlx4_en_set_tunable,
1300}; 1344};
1301 1345
1302 1346
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 0c501253fdab..92a7cf46d9af 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -37,6 +37,7 @@
37#include <linux/mlx4/qp.h> 37#include <linux/mlx4/qp.h>
38#include <linux/skbuff.h> 38#include <linux/skbuff.h>
39#include <linux/if_vlan.h> 39#include <linux/if_vlan.h>
40#include <linux/prefetch.h>
40#include <linux/vmalloc.h> 41#include <linux/vmalloc.h>
41#include <linux/tcp.h> 42#include <linux/tcp.h>
42#include <linux/ip.h> 43#include <linux/ip.h>
@@ -65,10 +66,9 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
65 ring->size = size; 66 ring->size = size;
66 ring->size_mask = size - 1; 67 ring->size_mask = size - 1;
67 ring->stride = stride; 68 ring->stride = stride;
68 ring->inline_thold = priv->prof->inline_thold;
69 69
70 tmp = size * sizeof(struct mlx4_en_tx_info); 70 tmp = size * sizeof(struct mlx4_en_tx_info);
71 ring->tx_info = vmalloc_node(tmp, node); 71 ring->tx_info = kmalloc_node(tmp, GFP_KERNEL | __GFP_NOWARN, node);
72 if (!ring->tx_info) { 72 if (!ring->tx_info) {
73 ring->tx_info = vmalloc(tmp); 73 ring->tx_info = vmalloc(tmp);
74 if (!ring->tx_info) { 74 if (!ring->tx_info) {
@@ -151,7 +151,7 @@ err_bounce:
151 kfree(ring->bounce_buf); 151 kfree(ring->bounce_buf);
152 ring->bounce_buf = NULL; 152 ring->bounce_buf = NULL;
153err_info: 153err_info:
154 vfree(ring->tx_info); 154 kvfree(ring->tx_info);
155 ring->tx_info = NULL; 155 ring->tx_info = NULL;
156err_ring: 156err_ring:
157 kfree(ring); 157 kfree(ring);
@@ -174,7 +174,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
174 mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); 174 mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
175 kfree(ring->bounce_buf); 175 kfree(ring->bounce_buf);
176 ring->bounce_buf = NULL; 176 ring->bounce_buf = NULL;
177 vfree(ring->tx_info); 177 kvfree(ring->tx_info);
178 ring->tx_info = NULL; 178 ring->tx_info = NULL;
179 kfree(ring); 179 kfree(ring);
180 *pring = NULL; 180 *pring = NULL;
@@ -191,12 +191,12 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
191 ring->prod = 0; 191 ring->prod = 0;
192 ring->cons = 0xffffffff; 192 ring->cons = 0xffffffff;
193 ring->last_nr_txbb = 1; 193 ring->last_nr_txbb = 1;
194 ring->poll_cnt = 0;
195 memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info)); 194 memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
196 memset(ring->buf, 0, ring->buf_size); 195 memset(ring->buf, 0, ring->buf_size);
197 196
198 ring->qp_state = MLX4_QP_STATE_RST; 197 ring->qp_state = MLX4_QP_STATE_RST;
199 ring->doorbell_qpn = ring->qp.qpn << 8; 198 ring->doorbell_qpn = cpu_to_be32(ring->qp.qpn << 8);
199 ring->mr_key = cpu_to_be32(mdev->mr.key);
200 200
201 mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, 201 mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
202 ring->cqn, user_prio, &ring->context); 202 ring->cqn, user_prio, &ring->context);
@@ -259,38 +259,45 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
259 struct mlx4_en_tx_ring *ring, 259 struct mlx4_en_tx_ring *ring,
260 int index, u8 owner, u64 timestamp) 260 int index, u8 owner, u64 timestamp)
261{ 261{
262 struct mlx4_en_dev *mdev = priv->mdev;
263 struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; 262 struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
264 struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; 263 struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
265 struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; 264 struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
266 struct sk_buff *skb = tx_info->skb;
267 struct skb_frag_struct *frag;
268 void *end = ring->buf + ring->buf_size; 265 void *end = ring->buf + ring->buf_size;
269 int frags = skb_shinfo(skb)->nr_frags; 266 struct sk_buff *skb = tx_info->skb;
267 int nr_maps = tx_info->nr_maps;
270 int i; 268 int i;
271 struct skb_shared_hwtstamps hwts;
272 269
273 if (timestamp) { 270 /* We do not touch skb here, so prefetch skb->users location
274 mlx4_en_fill_hwtstamps(mdev, &hwts, timestamp); 271 * to speedup consume_skb()
272 */
273 prefetchw(&skb->users);
274
275 if (unlikely(timestamp)) {
276 struct skb_shared_hwtstamps hwts;
277
278 mlx4_en_fill_hwtstamps(priv->mdev, &hwts, timestamp);
275 skb_