Skip to content

Commit

Permalink
Merge tag 'mlx5e-updates-2018-06-28' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
mlx5e-updates-2018-06-28

mlx5e netdevice driver updates:

- Boris Pismenny added the support for UDP GSO in the first two patches.
  Impressive performance numbers are included in the commit message,
  @Line rate with ~half of the cpu utilization compared to non offload
  or no GSO at all.

- From Tariq Toukan:
  - Convert large order kzalloc allocations to kvzalloc.
  - Added performance diagnostic statistics to several places in data path.

From Saeed and Eran,
  - Update NIC HW stats on demand only, this is to eliminate the background
    thread needed to update some HW statistics in the driver cache in
    order to report error and drop counters from HW in ndo_get_stats.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 29, 2018
2 parents c65a6a9 + ed56c51 commit 30408a4
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 48 deletions.
4 changes: 2 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
fpga/ipsec.o fpga/tls.o

mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
en_tx.o en_rx.o en_dim.o en_txrx.o en_stats.o vxlan.o \
en_arfs.o en_fs_ethtool.o en_selftest.o en/port.o
en_tx.o en_rx.o en_dim.o en_txrx.o en_accel/rxtx.o en_stats.o \
vxlan.o en_arfs.o en_fs_ethtool.o en_selftest.o en/port.o

mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o

Expand Down
1 change: 0 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ struct page_pool;
#define MLX5E_MAX_NUM_CHANNELS (MLX5E_INDIR_RQT_SIZE >> 1)
#define MLX5E_MAX_NUM_SQS (MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC)
#define MLX5E_TX_CQ_POLL_BUDGET 128
#define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */
#define MLX5E_SQ_RECOVER_MIN_INTERVAL 500 /* msecs */

#define MLX5E_UMR_WQE_INLINE_SZ \
Expand Down
11 changes: 7 additions & 4 deletions drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@
#ifndef __MLX5E_EN_ACCEL_H__
#define __MLX5E_EN_ACCEL_H__

#ifdef CONFIG_MLX5_ACCEL

#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "en_accel/ipsec_rxtx.h"
#include "en_accel/tls_rxtx.h"
#include "en_accel/rxtx.h"
#include "en.h"

static inline struct sk_buff *mlx5e_accel_handle_tx(struct sk_buff *skb,
Expand All @@ -64,9 +63,13 @@ static inline struct sk_buff *mlx5e_accel_handle_tx(struct sk_buff *skb,
}
#endif

if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
skb = mlx5e_udp_gso_handle_tx_skb(dev, sq, skb, wqe, pi);
if (unlikely(!skb))
return NULL;
}

return skb;
}

#endif /* CONFIG_MLX5_ACCEL */

#endif /* __MLX5E_EN_ACCEL_H__ */
109 changes: 109 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_accel/rxtx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "en_accel/rxtx.h"

static void mlx5e_udp_gso_prepare_last_skb(struct sk_buff *skb,
struct sk_buff *nskb,
int remaining)
{
int bytes_needed = remaining, remaining_headlen, remaining_page_offset;
int headlen = skb_transport_offset(skb) + sizeof(struct udphdr);
int payload_len = remaining + sizeof(struct udphdr);
int k = 0, i, j;

skb_copy_bits(skb, 0, nskb->data, headlen);
nskb->dev = skb->dev;
skb_reset_mac_header(nskb);
skb_set_network_header(nskb, skb_network_offset(skb));
skb_set_transport_header(nskb, skb_transport_offset(skb));
skb_set_tail_pointer(nskb, headlen);

/* How many frags do we need? */
for (i = skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) {
bytes_needed -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
k++;
if (bytes_needed <= 0)
break;
}

/* Fill the first frag and split it if necessary */
j = skb_shinfo(skb)->nr_frags - k;
remaining_page_offset = -bytes_needed;
skb_fill_page_desc(nskb, 0,
skb_shinfo(skb)->frags[j].page.p,
skb_shinfo(skb)->frags[j].page_offset + remaining_page_offset,
skb_shinfo(skb)->frags[j].size - remaining_page_offset);

skb_frag_ref(skb, j);

/* Fill the rest of the frags */
for (i = 1; i < k; i++) {
j = skb_shinfo(skb)->nr_frags - k + i;

skb_fill_page_desc(nskb, i,
skb_shinfo(skb)->frags[j].page.p,
skb_shinfo(skb)->frags[j].page_offset,
skb_shinfo(skb)->frags[j].size);
skb_frag_ref(skb, j);
}
skb_shinfo(nskb)->nr_frags = k;

remaining_headlen = remaining - skb->data_len;

/* headlen contains remaining data? */
if (remaining_headlen > 0)
skb_copy_bits(skb, skb->len - remaining, nskb->data + headlen,
remaining_headlen);
nskb->len = remaining + headlen;
nskb->data_len = payload_len - sizeof(struct udphdr) +
max_t(int, 0, remaining_headlen);
nskb->protocol = skb->protocol;
if (nskb->protocol == htons(ETH_P_IP)) {
ip_hdr(nskb)->id = htons(ntohs(ip_hdr(nskb)->id) +
skb_shinfo(skb)->gso_segs);
ip_hdr(nskb)->tot_len =
htons(payload_len + sizeof(struct iphdr));
} else {
ipv6_hdr(nskb)->payload_len = htons(payload_len);
}
udp_hdr(nskb)->len = htons(payload_len);
skb_shinfo(nskb)->gso_size = 0;
nskb->ip_summed = skb->ip_summed;
nskb->csum_start = skb->csum_start;
nskb->csum_offset = skb->csum_offset;
nskb->queue_mapping = skb->queue_mapping;
}

/* might send skbs and update wqe and pi */
struct sk_buff *mlx5e_udp_gso_handle_tx_skb(struct net_device *netdev,
struct mlx5e_txqsq *sq,
struct sk_buff *skb,
struct mlx5e_tx_wqe **wqe,
u16 *pi)
{
int payload_len = skb_shinfo(skb)->gso_size + sizeof(struct udphdr);
int headlen = skb_transport_offset(skb) + sizeof(struct udphdr);
int remaining = (skb->len - headlen) % skb_shinfo(skb)->gso_size;
struct sk_buff *nskb;

if (skb->protocol == htons(ETH_P_IP))
ip_hdr(skb)->tot_len = htons(payload_len + sizeof(struct iphdr));
else
ipv6_hdr(skb)->payload_len = htons(payload_len);
udp_hdr(skb)->len = htons(payload_len);
if (!remaining)
return skb;

sq->stats->udp_seg_rem++;
nskb = alloc_skb(max_t(int, headlen, headlen + remaining - skb->data_len), GFP_ATOMIC);
if (unlikely(!nskb)) {
sq->stats->dropped++;
return NULL;
}

mlx5e_udp_gso_prepare_last_skb(skb, nskb, remaining);

skb_shinfo(skb)->gso_segs--;
pskb_trim(skb, skb->len - remaining);
mlx5e_sq_xmit(sq, skb, *wqe, *pi);
mlx5e_sq_fetch_wqe(sq, wqe, pi);
return nskb;
}
14 changes: 14 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_accel/rxtx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

#ifndef __MLX5E_EN_ACCEL_RX_TX_H__
#define __MLX5E_EN_ACCEL_RX_TX_H__

#include <linux/skbuff.h>
#include "en.h"

struct sk_buff *mlx5e_udp_gso_handle_tx_skb(struct net_device *netdev,
struct mlx5e_txqsq *sq,
struct sk_buff *skb,
struct mlx5e_tx_wqe **wqe,
u16 *pi);

#endif
57 changes: 30 additions & 27 deletions drivers/net/ethernet/mellanox/mlx5/core/en_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,9 @@ void mlx5e_update_stats_work(struct work_struct *work)
struct delayed_work *dwork = to_delayed_work(work);
struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv,
update_stats_work);

mutex_lock(&priv->state_lock);
if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
priv->profile->update_stats(priv);
queue_delayed_work(priv->wq, dwork,
msecs_to_jiffies(MLX5E_UPDATE_STATS_INTERVAL));
}
priv->profile->update_stats(priv);
mutex_unlock(&priv->state_lock);
}

Expand Down Expand Up @@ -352,8 +349,8 @@ static int mlx5e_rq_alloc_mpwqe_info(struct mlx5e_rq *rq,
{
int wq_sz = mlx5_wq_ll_get_size(&rq->mpwqe.wq);

rq->mpwqe.info = kcalloc_node(wq_sz, sizeof(*rq->mpwqe.info),
GFP_KERNEL, cpu_to_node(c->cpu));
rq->mpwqe.info = kvzalloc_node(wq_sz * sizeof(*rq->mpwqe.info),
GFP_KERNEL, cpu_to_node(c->cpu));
if (!rq->mpwqe.info)
return -ENOMEM;

Expand Down Expand Up @@ -670,7 +667,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
err_free:
switch (rq->wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
kfree(rq->mpwqe.info);
kvfree(rq->mpwqe.info);
mlx5_core_destroy_mkey(mdev, &rq->umr_mkey);
break;
default: /* MLX5_WQ_TYPE_CYCLIC */
Expand Down Expand Up @@ -702,7 +699,7 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq)

switch (rq->wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
kfree(rq->mpwqe.info);
kvfree(rq->mpwqe.info);
mlx5_core_destroy_mkey(rq->mdev, &rq->umr_mkey);
break;
default: /* MLX5_WQ_TYPE_CYCLIC */
Expand Down Expand Up @@ -965,15 +962,15 @@ static void mlx5e_close_rq(struct mlx5e_rq *rq)

static void mlx5e_free_xdpsq_db(struct mlx5e_xdpsq *sq)
{
kfree(sq->db.di);
kvfree(sq->db.di);
}

static int mlx5e_alloc_xdpsq_db(struct mlx5e_xdpsq *sq, int numa)
{
int wq_sz = mlx5_wq_cyc_get_size(&sq->wq);

sq->db.di = kcalloc_node(wq_sz, sizeof(*sq->db.di),
GFP_KERNEL, numa);
sq->db.di = kvzalloc_node(sizeof(*sq->db.di) * wq_sz,
GFP_KERNEL, numa);
if (!sq->db.di) {
mlx5e_free_xdpsq_db(sq);
return -ENOMEM;
Expand Down Expand Up @@ -1024,15 +1021,15 @@ static void mlx5e_free_xdpsq(struct mlx5e_xdpsq *sq)

static void mlx5e_free_icosq_db(struct mlx5e_icosq *sq)
{
kfree(sq->db.ico_wqe);
kvfree(sq->db.ico_wqe);
}

static int mlx5e_alloc_icosq_db(struct mlx5e_icosq *sq, int numa)
{
u8 wq_sz = mlx5_wq_cyc_get_size(&sq->wq);

sq->db.ico_wqe = kcalloc_node(wq_sz, sizeof(*sq->db.ico_wqe),
GFP_KERNEL, numa);
sq->db.ico_wqe = kvzalloc_node(sizeof(*sq->db.ico_wqe) * wq_sz,
GFP_KERNEL, numa);
if (!sq->db.ico_wqe)
return -ENOMEM;

Expand Down Expand Up @@ -1077,19 +1074,19 @@ static void mlx5e_free_icosq(struct mlx5e_icosq *sq)

static void mlx5e_free_txqsq_db(struct mlx5e_txqsq *sq)
{
kfree(sq->db.wqe_info);
kfree(sq->db.dma_fifo);
kvfree(sq->db.wqe_info);
kvfree(sq->db.dma_fifo);
}

static int mlx5e_alloc_txqsq_db(struct mlx5e_txqsq *sq, int numa)
{
int wq_sz = mlx5_wq_cyc_get_size(&sq->wq);
int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS;

sq->db.dma_fifo = kcalloc_node(df_sz, sizeof(*sq->db.dma_fifo),
GFP_KERNEL, numa);
sq->db.wqe_info = kcalloc_node(wq_sz, sizeof(*sq->db.wqe_info),
GFP_KERNEL, numa);
sq->db.dma_fifo = kvzalloc_node(df_sz * sizeof(*sq->db.dma_fifo),
GFP_KERNEL, numa);
sq->db.wqe_info = kvzalloc_node(wq_sz * sizeof(*sq->db.wqe_info),
GFP_KERNEL, numa);
if (!sq->db.dma_fifo || !sq->db.wqe_info) {
mlx5e_free_txqsq_db(sq);
return -ENOMEM;
Expand Down Expand Up @@ -1893,7 +1890,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
int err;
int eqn;

c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
if (!c)
return -ENOMEM;

Expand Down Expand Up @@ -1979,7 +1976,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,

err_napi_del:
netif_napi_del(&c->napi);
kfree(c);
kvfree(c);

return err;
}
Expand Down Expand Up @@ -2018,7 +2015,7 @@ static void mlx5e_close_channel(struct mlx5e_channel *c)
mlx5e_close_cq(&c->icosq.cq);
netif_napi_del(&c->napi);

kfree(c);
kvfree(c);
}

#define DEFAULT_FRAG_SIZE (2048)
Expand Down Expand Up @@ -2276,7 +2273,7 @@ int mlx5e_open_channels(struct mlx5e_priv *priv,
chs->num = chs->params.num_channels;

chs->c = kcalloc(chs->num, sizeof(struct mlx5e_channel *), GFP_KERNEL);
cparam = kzalloc(sizeof(struct mlx5e_channel_param), GFP_KERNEL);
cparam = kvzalloc(sizeof(struct mlx5e_channel_param), GFP_KERNEL);
if (!chs->c || !cparam)
goto err_free;

Expand All @@ -2287,7 +2284,7 @@ int mlx5e_open_channels(struct mlx5e_priv *priv,
goto err_close_channels;
}

kfree(cparam);
kvfree(cparam);
return 0;

err_close_channels:
Expand All @@ -2296,7 +2293,7 @@ int mlx5e_open_channels(struct mlx5e_priv *priv,

err_free:
kfree(chs->c);
kfree(cparam);
kvfree(cparam);
chs->num = 0;
return err;
}
Expand Down Expand Up @@ -3405,6 +3402,9 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
struct mlx5e_vport_stats *vstats = &priv->stats.vport;
struct mlx5e_pport_stats *pstats = &priv->stats.pport;

/* update HW stats in background for next time */
queue_delayed_work(priv->wq, &priv->update_stats_work, 0);

if (mlx5e_is_uplink_rep(priv)) {
stats->rx_packets = PPORT_802_3_GET(pstats, a_frames_received_ok);
stats->rx_bytes = PPORT_802_3_GET(pstats, a_octets_received_ok);
Expand Down Expand Up @@ -4592,6 +4592,9 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
netdev->features |= NETIF_F_HIGHDMA;
netdev->features |= NETIF_F_HW_VLAN_STAG_FILTER;

netdev->features |= NETIF_F_GSO_UDP_L4;
netdev->hw_features |= NETIF_F_GSO_UDP_L4;

netdev->priv_flags |= IFF_UNICAST_FLT;

mlx5e_set_netdev_dev_addr(netdev);
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,9 @@ mlx5e_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct mlx5e_priv *priv = netdev_priv(dev);

/* update HW stats in background for next time */
queue_delayed_work(priv->wq, &priv->update_stats_work, 0);

memcpy(stats, &priv->stats.vf_vport, sizeof(*stats));
}

Expand Down
Loading

0 comments on commit 30408a4

Please sign in to comment.