History

Merge tag 'blk-dim-v2' into rdma.git for-next

Generic DIM From: Tal Gilboa and Yamin Fridman Implement net DIM over a generic DIM library, add RDMA DIM dim.h lib exposes an implementation of the DIM algorithm for dynamically-tuned interrupt moderation for networking interfaces. We want a similar functionality for other protocols, which might need to optimize interrupts differently. Main motivation here is DIM for NVMf storage protocol. Current DIM implementation prioritizes reducing interrupt overhead over latency. Also, in order to reduce DIM's own overhead, the algorithm might take some time to identify it needs to change profiles. While this is acceptable for networking, it might not work well on other scenarios. Here we propose a new structure to DIM. The idea is to allow a slightly modified functionality without the risk of breaking Net DIM behavior for netdev. We verified there are no degradations in current DIM behavior with the modified solution. Suggested solution: - Common logic is implemented in lib/dim/dim.c - Net DIM (existing) logic is implemented in lib/dim/net_dim.c, which uses the common logic in dim.c - Any new DIM logic will be implemented in "lib/dim/new_dim.c". This new implementation will expose modified versions of profiles, dim_step() and dim_decision(). - DIM API is declared in include/linux/dim.h for all implementations. Pros for this solution are: - Zero impact on existing net_dim implementation and usage - Relatively more code reuse (compared to two separate solutions) - Increased extensibility Required for dependencies in the next series.

Jason Gunthorpe committed 7 years ago

Commit 2ef38e32 parents 89705e9 398c2b023 files · +728 −489Browse files

Unified · Split

23 files
  1. MAINTAINERS +2 −1
  2. drivers/net/ethernet/broadcom/Kconfig +1 −0
  3. drivers/net/ethernet/broadcom/bcmsysport.c +10 −10
  4. drivers/net/ethernet/broadcom/bcmsysport.h +2 −2
  5. drivers/net/ethernet/broadcom/bnxt/bnxt.c +6 −6
  6. drivers/net/ethernet/broadcom/bnxt/bnxt.h +2 −2
  7. drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c +3 −3
  8. drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c +4 −5
  9. drivers/net/ethernet/broadcom/genet/bcmgenet.c +9 −9
  10. drivers/net/ethernet/broadcom/genet/bcmgenet.h +2 −2
  11. drivers/net/ethernet/mellanox/mlx5/core/Kconfig +1 −0
  12. drivers/net/ethernet/mellanox/mlx5/core/en.h +5 −5
  13. drivers/net/ethernet/mellanox/mlx5/core/en_dim.c +7 −7
  14. drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +2 −2
  15. drivers/net/ethernet/mellanox/mlx5/core/en_main.c +11 −11
  16. drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +4 −6
  17. include/linux/dim.h +366 −0
  18. include/linux/net_dim.h +0 −418
  19. lib/Kconfig +8 −0
  20. lib/Makefile +1 −0
  21. lib/dim/Makefile +9 −0
  22. lib/dim/dim.c +83 −0
  23. lib/dim/net_dim.c +190 −0
MAINTAINERS+2−1
@@ -5600,7 +5600,8 @@ F: include/linux/dynamic_debug.h · 5599 unmodified lines
56005600 DYNAMIC INTERRUPT MODERATION
56015601 M: Tal Gilboa <talgi@mellanox.com>
56025602 S: Maintained
5603−F: include/linux/net_dim.h
5603+F: include/linux/dim.h
5604+F: lib/dim/
56045605
56055606 DZ DECSTATION DZ11 SERIAL DRIVER
56065607 M: "Maciej W. Rozycki" <macro@linux-mips.org>
drivers/net/ethernet/broadcom/Kconfig+1−0
@@ -8,6 +8,7 @@ config NET_VENDOR_BROADCOM · 7 unmodified lines
88 default y
99 depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \
1010 SIBYTE_SB1xxx_SOC
11+ select DIMLIB
1112 ---help---
1213 If you have a network (Ethernet) chipset belonging to this class,
1314 say Y.
drivers/net/ethernet/broadcom/bcmsysport.c+10−10
@@ -609,7 +609,7 @@ static int bcm_sysport_set_coalesce(struct net_device *dev, · 608 unmodified lines
609609 struct ethtool_coalesce *ec)
610610 {
611611 struct bcm_sysport_priv *priv = netdev_priv(dev);
612− struct net_dim_cq_moder moder;
612+ struct dim_cq_moder moder;
613613 u32 usecs, pkts;
614614 unsigned int i;
615615
@@ -992,7 +992,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget) · 376 unmodified lines
992992 {
993993 struct bcm_sysport_priv *priv =
994994 container_of(napi, struct bcm_sysport_priv, napi);
995− struct net_dim_sample dim_sample;
995+ struct dim_sample dim_sample;
996996 unsigned int work_done = 0;
997997
998998 work_done = bcm_sysport_desc_rx(priv, budget);
@@ -1016,8 +1016,8 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget) · 17 unmodified lines
10161016 }
10171017
10181018 if (priv->dim.use_dim) {
1019− net_dim_sample(priv->dim.event_ctr, priv->dim.packets,
1020− priv->dim.bytes, &dim_sample);
1019+ dim_update_sample(priv->dim.event_ctr, priv->dim.packets,
1020+ priv->dim.bytes, &dim_sample);
10211021 net_dim(&priv->dim.dim, dim_sample);
10221022 }
10231023
@@ -1087,16 +1087,16 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv) · 63 unmodified lines
10871087
10881088 static void bcm_sysport_dim_work(struct work_struct *work)
10891089 {
1090− struct net_dim *dim = container_of(work, struct net_dim, work);
1090+ struct dim *dim = container_of(work, struct dim, work);
10911091 struct bcm_sysport_net_dim *ndim =
10921092 container_of(dim, struct bcm_sysport_net_dim, dim);
10931093 struct bcm_sysport_priv *priv =
10941094 container_of(ndim, struct bcm_sysport_priv, dim);
1095− struct net_dim_cq_moder cur_profile =
1096− net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
1095+ struct dim_cq_moder cur_profile = net_dim_get_rx_moderation(dim->mode,
1096+ dim->profile_ix);
10971097
10981098 bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts);
1099− dim->state = NET_DIM_START_MEASURE;
1099+ dim->state = DIM_START_MEASURE;
11001100 }
11011101
11021102 /* RX and misc interrupt routine */
@@ -1437,7 +1437,7 @@ static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv, · 334 unmodified lines
14371437 struct bcm_sysport_net_dim *dim = &priv->dim;
14381438
14391439 INIT_WORK(&dim->dim.work, cb);
1440− dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
1440+ dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
14411441 dim->event_ctr = 0;
14421442 dim->packets = 0;
14431443 dim->bytes = 0;
@@ -1446,7 +1446,7 @@ static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv, · 2 unmodified lines
14461446 static void bcm_sysport_init_rx_coalesce(struct bcm_sysport_priv *priv)
14471447 {
14481448 struct bcm_sysport_net_dim *dim = &priv->dim;
1449− struct net_dim_cq_moder moder;
1449+ struct dim_cq_moder moder;
14501450 u32 usecs, pkts;
14511451
14521452 usecs = priv->rx_coalesce_usecs;
drivers/net/ethernet/broadcom/bcmsysport.h+2−2
@@ -11,7 +11,7 @@ · 10 unmodified lines
1111 #include <linux/bitmap.h>
1212 #include <linux/ethtool.h>
1313 #include <linux/if_vlan.h>
14−#include <linux/net_dim.h>
14+#include <linux/dim.h>
1515
1616 /* Receive/transmit descriptor format */
1717 #define DESC_ADDR_HI_STATUS_LEN 0x00
@@ -702,7 +702,7 @@ struct bcm_sysport_net_dim { · 684 unmodified lines
702702 u16 event_ctr;
703703 unsigned long packets;
704704 unsigned long bytes;
705− struct net_dim dim;
705+ struct dim dim;
706706 };
707707
708708 /* Software view of the TX ring */
drivers/net/ethernet/broadcom/bnxt/bnxt.c+6−6
@@ -2130,12 +2130,12 @@ static int bnxt_poll(struct napi_struct *napi, int budget) · 2129 unmodified lines
21302130 }
21312131 }
21322132 if (bp->flags & BNXT_FLAG_DIM) {
2133− struct net_dim_sample dim_sample;
2133+ struct dim_sample dim_sample;
21342134
2135− net_dim_sample(cpr->event_ctr,
2136− cpr->rx_packets,
2137− cpr->rx_bytes,
2138− &dim_sample);
2135+ dim_update_sample(cpr->event_ctr,
2136+ cpr->rx_packets,
2137+ cpr->rx_bytes,
2138+ &dim_sample);
21392139 net_dim(&cpr->dim, dim_sample);
21402140 }
21412141 return work_done;
@@ -7813,7 +7813,7 @@ static void bnxt_enable_napi(struct bnxt *bp) · 5671 unmodified lines
78137813
78147814 if (bp->bnapi[i]->rx_ring) {
78157815 INIT_WORK(&cpr->dim.work, bnxt_dim_work);
7816− cpr->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
7816+ cpr->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
78177817 }
78187818 napi_enable(&bp->bnapi[i]->napi);
78197819 }
drivers/net/ethernet/broadcom/bnxt/bnxt.h+2−2
@@ -24,7 +24,7 @@ · 23 unmodified lines
2424 #include <net/devlink.h>
2525 #include <net/dst_metadata.h>
2626 #include <net/xdp.h>
27−#include <linux/net_dim.h>
27+#include <linux/dim.h>
2828
2929 struct tx_bd {
3030 __le32 tx_bd_len_flags_type;
@@ -810,7 +810,7 @@ struct bnxt_cp_ring_info { · 779 unmodified lines
810810 u64 rx_bytes;
811811 u64 event_ctr;
812812
813− struct net_dim dim;
813+ struct dim dim;
814814
815815 union {
816816 struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c+3−3
@@ -11,7 +11,7 @@ · 10 unmodified lines
1111 #include <linux/module.h>
1212 #include <linux/pci.h>
1313 #include "bnxt_hsi.h"
14−#include <linux/net_dim.h>
14+#include <linux/dim.h>
1515 #include "bnxt.h"
1616 #include "bnxt_debugfs.h"
1717
@@ -21,7 +21,7 @@ static ssize_t debugfs_dim_read(struct file *filep, · 3 unmodified lines
2121 char __user *buffer,
2222 size_t count, loff_t *ppos)
2323 {
24− struct net_dim *dim = filep->private_data;
24+ struct dim *dim = filep->private_data;
2525 int len;
2626 char *buf;
2727
@@ -61,7 +61,7 @@ static const struct file_operations debugfs_dim_fops = { · 33 unmodified lines
6161 .read = debugfs_dim_read,
6262 };
6363
64−static struct dentry *debugfs_dim_ring_init(struct net_dim *dim, int ring_idx,
64+static struct dentry *debugfs_dim_ring_init(struct dim *dim, int ring_idx,
6565 struct dentry *dd)
6666 {
6767 static char qname[16];
drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c+4−5
@@ -7,26 +7,25 @@ · 6 unmodified lines
77 * the Free Software Foundation.
88 */
99
10−#include <linux/net_dim.h>
10+#include <linux/dim.h>
1111 #include "bnxt_hsi.h"
1212 #include "bnxt.h"
1313
1414 void bnxt_dim_work(struct work_struct *work)
1515 {
16− struct net_dim *dim = container_of(work, struct net_dim,
17− work);
16+ struct dim *dim = container_of(work, struct dim, work);
1817 struct bnxt_cp_ring_info *cpr = container_of(dim,
1918 struct bnxt_cp_ring_info,
2019 dim);
2120 struct bnxt_napi *bnapi = container_of(cpr,
2221 struct bnxt_napi,
2322 cp_ring);
24− struct net_dim_cq_moder cur_moder =
23+ struct dim_cq_moder cur_moder =
2524 net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
2625
2726 cpr->rx_ring_coal.coal_ticks = cur_moder.usec;
2827 cpr->rx_ring_coal.coal_bufs = cur_moder.pkts;
2928
3029 bnxt_hwrm_set_ring_coal(bnapi->bp, bnapi);
31− dim->state = NET_DIM_START_MEASURE;
30+ dim->state = DIM_START_MEASURE;
3231 }
drivers/net/ethernet/broadcom/genet/bcmgenet.c+9−9
@@ -640,7 +640,7 @@ static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring, · 639 unmodified lines
640640 static void bcmgenet_set_ring_rx_coalesce(struct bcmgenet_rx_ring *ring,
641641 struct ethtool_coalesce *ec)
642642 {
643− struct net_dim_cq_moder moder;
643+ struct dim_cq_moder moder;
644644 u32 usecs, pkts;
645645
646646 ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
@@ -1895,7 +1895,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) · 1248 unmodified lines
18951895 {
18961896 struct bcmgenet_rx_ring *ring = container_of(napi,
18971897 struct bcmgenet_rx_ring, napi);
1898− struct net_dim_sample dim_sample;
1898+ struct dim_sample dim_sample;
18991899 unsigned int work_done;
19001900
19011901 work_done = bcmgenet_desc_rx(ring, budget);
@@ -1906,8 +1906,8 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) · 4 unmodified lines
19061906 }
19071907
19081908 if (ring->dim.use_dim) {
1909− net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
1910− ring->dim.bytes, &dim_sample);
1909+ dim_update_sample(ring->dim.event_ctr, ring->dim.packets,
1910+ ring->dim.bytes, &dim_sample);
19111911 net_dim(&ring->dim.dim, dim_sample);
19121912 }
19131913
@@ -1916,16 +1916,16 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) · 2 unmodified lines
19161916
19171917 static void bcmgenet_dim_work(struct work_struct *work)
19181918 {
1919− struct net_dim *dim = container_of(work, struct net_dim, work);
1919+ struct dim *dim = container_of(work, struct dim, work);
19201920 struct bcmgenet_net_dim *ndim =
19211921 container_of(dim, struct bcmgenet_net_dim, dim);
19221922 struct bcmgenet_rx_ring *ring =
19231923 container_of(ndim, struct bcmgenet_rx_ring, dim);
1924− struct net_dim_cq_moder cur_profile =
1924+ struct dim_cq_moder cur_profile =
19251925 net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
19261926
19271927 bcmgenet_set_rx_coalesce(ring, cur_profile.usec, cur_profile.pkts);
1928− dim->state = NET_DIM_START_MEASURE;
1928+ dim->state = DIM_START_MEASURE;
19291929 }
19301930
19311931 /* Assign skb to RX DMA descriptor. */
@@ -2082,7 +2082,7 @@ static void bcmgenet_init_dim(struct bcmgenet_rx_ring *ring, · 150 unmodified lines
20822082 struct bcmgenet_net_dim *dim = &ring->dim;
20832083
20842084 INIT_WORK(&dim->dim.work, cb);
2085− dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
2085+ dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
20862086 dim->event_ctr = 0;
20872087 dim->packets = 0;
20882088 dim->bytes = 0;
@@ -2091,7 +2091,7 @@ static void bcmgenet_init_dim(struct bcmgenet_rx_ring *ring, · 2 unmodified lines
20912091 static void bcmgenet_init_rx_coalesce(struct bcmgenet_rx_ring *ring)
20922092 {
20932093 struct bcmgenet_net_dim *dim = &ring->dim;
2094− struct net_dim_cq_moder moder;
2094+ struct dim_cq_moder moder;
20952095 u32 usecs, pkts;
20962096
20972097 usecs = ring->rx_coalesce_usecs;
drivers/net/ethernet/broadcom/genet/bcmgenet.h+2−2
@@ -13,7 +13,7 @@ · 12 unmodified lines
1313 #include <linux/mii.h>
1414 #include <linux/if_vlan.h>
1515 #include <linux/phy.h>
16−#include <linux/net_dim.h>
16+#include <linux/dim.h>
1717
1818 /* total number of Buffer Descriptors, same for Rx/Tx */
1919 #define TOTAL_DESC 256
@@ -578,7 +578,7 @@ struct bcmgenet_net_dim { · 558 unmodified lines
578578 u16 event_ctr;
579579 unsigned long packets;
580580 unsigned long bytes;
581− struct net_dim dim;
581+ struct dim dim;
582582 };
583583
584584 struct bcmgenet_rx_ring {
drivers/net/ethernet/mellanox/mlx5/core/Kconfig+1−0
@@ -34,6 +34,7 @@ config MLX5_CORE_EN · 33 unmodified lines
3434 depends on NETDEVICES && ETHERNET && INET && PCI && MLX5_CORE
3535 depends on IPV6=y || IPV6=n || MLX5_CORE=m
3636 select PAGE_POOL
37+ select DIMLIB
3738 default n
3839 ---help---
3940 Ethernet support in Mellanox Technologies ConnectX-4 NIC.
drivers/net/ethernet/mellanox/mlx5/core/en.h+5−5
@@ -48,7 +48,7 @@ · 47 unmodified lines
4848 #include <linux/rhashtable.h>
4949 #include <net/switchdev.h>
5050 #include <net/xdp.h>
51−#include <linux/net_dim.h>
51+#include <linux/dim.h>
5252 #include <linux/bits.h>
5353 #include "wq.h"
5454 #include "mlx5_core.h"
@@ -238,9 +238,9 @@ struct mlx5e_params { · 183 unmodified lines
238238 u16 num_channels;
239239 u8 num_tc;
240240 bool rx_cqe_compress_def;
241− struct net_dim_cq_moder rx_cq_moderation;
242− struct net_dim_cq_moder tx_cq_moderation;
243241 bool tunneled_offload_en;
242+ struct dim_cq_moder rx_cq_moderation;
243+ struct dim_cq_moder tx_cq_moderation;
244244 bool lro_en;
245245 u8 tx_min_inline_mode;
246246 bool vlan_strip_disable;
@@ -356,7 +356,7 @@ struct mlx5e_txqsq { · 109 unmodified lines
356356 /* dirtied @completion */
357357 u16 cc;
358358 u32 dma_fifo_cc;
359− struct net_dim dim; /* Adaptive Moderation */
359+ struct dim dim; /* Adaptive Moderation */
360360
361361 /* dirtied @xmit */
362362 u16 pc ____cacheline_aligned_in_smp;
@@ -596,7 +596,7 @@ struct mlx5e_rq { · 233 unmodified lines
596596 int ix;
597597 unsigned int hw_mtu;
598598
599− struct net_dim dim; /* Dynamic Interrupt Moderation */
599+ struct dim dim; /* Dynamic Interrupt Moderation */
600600
601601 /* XDP */
602602 struct bpf_prog *xdp_prog;
drivers/net/ethernet/mellanox/mlx5/core/en_dim.c+7−7
@@ -30,22 +30,22 @@ · 29 unmodified lines
3030 * SOFTWARE.
3131 */
3232
33−#include <linux/net_dim.h>
33+#include <linux/dim.h>
3434 #include "en.h"
3535
3636 static void
37−mlx5e_complete_dim_work(struct net_dim *dim, struct net_dim_cq_moder moder,
37+mlx5e_complete_dim_work(struct dim *dim, struct dim_cq_moder moder,
3838 struct mlx5_core_dev *mdev, struct mlx5_core_cq *mcq)
3939 {
4040 mlx5_core_modify_cq_moderation(mdev, mcq, moder.usec, moder.pkts);
41− dim->state = NET_DIM_START_MEASURE;
41+ dim->state = DIM_START_MEASURE;
4242 }
4343
4444 void mlx5e_rx_dim_work(struct work_struct *work)
4545 {
46− struct net_dim *dim = container_of(work, struct net_dim, work);
46+ struct dim *dim = container_of(work, struct dim, work);
4747 struct mlx5e_rq *rq = container_of(dim, struct mlx5e_rq, dim);
48− struct net_dim_cq_moder cur_moder =
48+ struct dim_cq_moder cur_moder =
4949 net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
5050
5151 mlx5e_complete_dim_work(dim, cur_moder, rq->mdev, &rq->cq.mcq);
@@ -53,9 +53,9 @@ void mlx5e_rx_dim_work(struct work_struct *work) · 1 unmodified line
5353
5454 void mlx5e_tx_dim_work(struct work_struct *work)
5555 {
56− struct net_dim *dim = container_of(work, struct net_dim, work);
56+ struct dim *dim = container_of(work, struct dim, work);
5757 struct mlx5e_txqsq *sq = container_of(dim, struct mlx5e_txqsq, dim);
58− struct net_dim_cq_moder cur_moder =
58+ struct dim_cq_moder cur_moder =
5959 net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
6060
6161 mlx5e_complete_dim_work(dim, cur_moder, sq->cq.mdev, &sq->cq.mcq);
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c+2−2
@@ -466,7 +466,7 @@ static int mlx5e_set_channels(struct net_device *dev, · 465 unmodified lines
466466 int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
467467 struct ethtool_coalesce *coal)
468468 {
469− struct net_dim_cq_moder *rx_moder, *tx_moder;
469+ struct dim_cq_moder *rx_moder, *tx_moder;
470470
471471 if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
472472 return -EOPNOTSUPP;
@@ -521,7 +521,7 @@ mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesc · 48 unmodified lines
521521 int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
522522 struct ethtool_coalesce *coal)
523523 {
524− struct net_dim_cq_moder *rx_moder, *tx_moder;
524+ struct dim_cq_moder *rx_moder, *tx_moder;
525525 struct mlx5_core_dev *mdev = priv->mdev;
526526 struct mlx5e_channels new_channels = {};
527527 int err = 0;
drivers/net/ethernet/mellanox/mlx5/core/en_main.c+11−11
@@ -584,11 +584,11 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, · 583 unmodified lines
584584
585585 switch (params->rx_cq_moderation.cq_period_mode) {
586586 case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
587− rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE;
587+ rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
588588 break;
589589 case MLX5_CQ_PERIOD_MODE_START_FROM_EQE:
590590 default:
591− rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
591+ rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
592592 }
593593
594594 rq->page_cache.head = 0;
@@ -1571,7 +1571,7 @@ static void mlx5e_destroy_cq(struct mlx5e_cq *cq) · 976 unmodified lines
15711571 }
15721572
15731573 static int mlx5e_open_cq(struct mlx5e_channel *c,
1574− struct net_dim_cq_moder moder,
1574+ struct dim_cq_moder moder,
15751575 struct mlx5e_cq_param *param,
15761576 struct mlx5e_cq *cq)
15771577 {
@@ -1776,7 +1776,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, · 198 unmodified lines
17761776 struct mlx5e_channel **cp)
17771777 {
17781778 int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
1779− struct net_dim_cq_moder icocq_moder = {0, 0};
1779+ struct dim_cq_moder icocq_moder = {0, 0};
17801780 struct net_device *netdev = priv->netdev;
17811781 struct mlx5e_channel *c;
17821782 unsigned int irq;
@@ -2153,7 +2153,7 @@ static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv, · 370 unmodified lines
21532153
21542154 mlx5e_build_common_cq_param(priv, param);
21552155
2156− param->cq_period_mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
2156+ param->cq_period_mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
21572157 }
21582158
21592159 static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
@@ -4421,9 +4421,9 @@ static bool slow_pci_heuristic(struct mlx5_core_dev *mdev) · 2261 unmodified lines
44214421 link_speed > MLX5E_SLOW_PCI_RATIO * pci_bw;
44224422 }
44234423
4424−static struct net_dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
4424+static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
44254425 {
4426− struct net_dim_cq_moder moder;
4426+ struct dim_cq_moder moder;
44274427
44284428 moder.cq_period_mode = cq_period_mode;
44294429 moder.pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
@@ -4434,9 +4434,9 @@ static struct net_dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode) · 4 unmodified lines
44344434 return moder;
44354435 }
44364436
4437−static struct net_dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
4437+static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
44384438 {
4439− struct net_dim_cq_moder moder;
4439+ struct dim_cq_moder moder;
44404440
44414441 moder.cq_period_mode = cq_period_mode;
44424442 moder.pkts = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
@@ -4450,8 +4450,8 @@ static struct net_dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode) · 7 unmodified lines
44504450 static u8 mlx5_to_net_dim_cq_period_mode(u8 cq_period_mode)
44514451 {
44524452 return cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE ?
4453− NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE :
4454− NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
4453+ DIM_CQ_PERIOD_MODE_START_FROM_CQE :
4454+ DIM_CQ_PERIOD_MODE_START_FROM_EQE;
44554455 }
44564456
44574457 void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c+4−6
@@ -48,26 +48,24 @@ static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c) · 47 unmodified lines
4848 static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
4949 {
5050 struct mlx5e_sq_stats *stats = sq->stats;
51− struct net_dim_sample dim_sample;
51+ struct dim_sample dim_sample;
5252
5353 if (unlikely(!test_bit(MLX5E_SQ_STATE_AM, &sq->state)))
5454 return;
5555
56− net_dim_sample(sq->cq.event_ctr, stats->packets, stats->bytes,
57− &dim_sample);
56+ dim_update_sample(sq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
5857 net_dim(&sq->dim, dim_sample);
5958 }
6059
6160 static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
6261 {
6362 struct mlx5e_rq_stats *stats = rq->stats;
64− struct net_dim_sample dim_sample;
63+ struct dim_sample dim_sample;
6564
6665 if (unlikely(!test_bit(MLX5E_RQ_STATE_AM, &rq->state)))
6766 return;
6867
69− net_dim_sample(rq->cq.event_ctr, stats->packets, stats->bytes,
70− &dim_sample);
68+ dim_update_sample(rq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
7169 net_dim(&rq->dim, dim_sample);
7270 }
7371
include/linux/dim.h+366−0
@@ -0,0 +1,366 @@
1+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+/* Copyright (c) 2019 Mellanox Technologies. */
3+
4+#ifndef DIM_H
5+#define DIM_H
6+
7+#include <linux/module.h>
8+
9+/**
10+ * Number of events between DIM iterations.
11+ * Causes a moderation of the algorithm run.
12+ */
13+#define DIM_NEVENTS 64
14+
15+/**
16+ * Is a difference between values justifies taking an action.
17+ * We consider 10% difference as significant.
18+ */
19+#define IS_SIGNIFICANT_DIFF(val, ref) \
20+ (((100UL * abs((val) - (ref))) / (ref)) > 10)
21+
22+/**
23+ * Calculate the gap between two values.
24+ * Take wrap-around and variable size into consideration.
25+ */
26+#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) \
27+ & (BIT_ULL(bits) - 1))
28+
29+/**
30+ * Structure for CQ moderation values.
31+ * Used for communications between DIM and its consumer.
32+ *
33+ * @usec: CQ timer suggestion (by DIM)
34+ * @pkts: CQ packet counter suggestion (by DIM)
35+ * @cq_period_mode: CQ priod count mode (from CQE/EQE)
36+ */
37+struct dim_cq_moder {
38+ u16 usec;
39+ u16 pkts;
40+ u16 comps;
41+ u8 cq_period_mode;
42+};
43+
44+/**
45+ * Structure for DIM sample data.
46+ * Used for communications between DIM and its consumer.
47+ *
48+ * @time: Sample timestamp
49+ * @pkt_ctr: Number of packets
50+ * @byte_ctr: Number of bytes
51+ * @event_ctr: Number of events
52+ */
53+struct dim_sample {
54+ ktime_t time;
55+ u32 pkt_ctr;
56+ u32 byte_ctr;
57+ u16 event_ctr;
58+ u32 comp_ctr;
59+};
60+
61+/**
62+ * Structure for DIM stats.
63+ * Used for holding current measured rates.
64+ *
65+ * @ppms: Packets per msec
66+ * @bpms: Bytes per msec
67+ * @epms: Events per msec
68+ */
69+struct dim_stats {
70+ int ppms; /* packets per msec */
71+ int bpms; /* bytes per msec */
72+ int epms; /* events per msec */
73+ int cpms; /* completions per msec */
74+ int cpe_ratio; /* ratio of completions to events */
75+};
76+
77+/**
78+ * Main structure for dynamic interrupt moderation (DIM).
79+ * Used for holding all information about a specific DIM instance.
80+ *
81+ * @state: Algorithm state (see below)
82+ * @prev_stats: Measured rates from previous iteration (for comparison)
83+ * @start_sample: Sampled data at start of current iteration
84+ * @work: Work to perform on action required
85+ * @profile_ix: Current moderation profile
86+ * @mode: CQ period count mode
87+ * @tune_state: Algorithm tuning state (see below)
88+ * @steps_right: Number of steps taken towards higher moderation
89+ * @steps_left: Number of steps taken towards lower moderation
90+ * @tired: Parking depth counter
91+ */
92+struct dim {
93+ u8 state;
94+ struct dim_stats prev_stats;
95+ struct dim_sample start_sample;
96+ struct dim_sample measuring_sample;
97+ struct work_struct work;
98+ u8 profile_ix;
99+ u8 mode;
100+ u8 tune_state;
101+ u8 steps_right;
102+ u8 steps_left;
103+ u8 tired;
104+};
105+
106+/**
107+ * enum dim_cq_period_mode
108+ *
109+ * These are the modes for CQ period count.
110+ *
111+ * @DIM_CQ_PERIOD_MODE_START_FROM_EQE: Start counting from EQE
112+ * @DIM_CQ_PERIOD_MODE_START_FROM_CQE: Start counting from CQE (implies timer reset)
113+ * @DIM_CQ_PERIOD_NUM_MODES: Number of modes
114+ */
115+enum {
116+ DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
117+ DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
118+ DIM_CQ_PERIOD_NUM_MODES
119+};
120+
121+/**
122+ * enum dim_state
123+ *
124+ * These are the DIM algorithm states.
125+ * These will determine if the algorithm is in a valid state to start an iteration.
126+ *
127+ * @DIM_START_MEASURE: This is the first iteration (also after applying a new profile)
128+ * @DIM_MEASURE_IN_PROGRESS: Algorithm is already in progress - check if
129+ * need to perform an action
130+ * @DIM_APPLY_NEW_PROFILE: DIM consumer is currently applying a profile - no need to measure
131+ */
132+enum {
133+ DIM_START_MEASURE,
134+ DIM_MEASURE_IN_PROGRESS,
135+ DIM_APPLY_NEW_PROFILE,
136+};
137+
138+/**
139+ * enum dim_tune_state
140+ *
141+ * These are the DIM algorithm tune states.
142+ * These will determine which action the algorithm should perform.
143+ *
144+ * @DIM_PARKING_ON_TOP: Algorithm found a local top point - exit on significant difference
145+ * @DIM_PARKING_TIRED: Algorithm found a deep top point - don't exit if tired > 0
146+ * @DIM_GOING_RIGHT: Algorithm is currently trying higher moderation levels
147+ * @DIM_GOING_LEFT: Algorithm is currently trying lower moderation levels
148+ */
149+enum {
150+ DIM_PARKING_ON_TOP,
151+ DIM_PARKING_TIRED,
152+ DIM_GOING_RIGHT,
153+ DIM_GOING_LEFT,
154+};
155+
156+/**
157+ * enum dim_stats_state
158+ *
159+ * These are the DIM algorithm statistics states.
160+ * These will determine the verdict of current iteration.
161+ *
162+ * @DIM_STATS_WORSE: Current iteration shows worse performance than before
163+ * @DIM_STATS_WORSE: Current iteration shows same performance than before
164+ * @DIM_STATS_WORSE: Current iteration shows better performance than before
165+ */
166+enum {
167+ DIM_STATS_WORSE,
168+ DIM_STATS_SAME,
169+ DIM_STATS_BETTER,
170+};
171+
172+/**
173+ * enum dim_step_result
174+ *
175+ * These are the DIM algorithm step results.
176+ * These describe the result of a step.
177+ *
178+ * @DIM_STEPPED: Performed a regular step
179+ * @DIM_TOO_TIRED: Same kind of step was done multiple times - should go to
180+ * tired parking
181+ * @DIM_ON_EDGE: Stepped to the most left/right profile
182+ */
183+enum {
184+ DIM_STEPPED,
185+ DIM_TOO_TIRED,
186+ DIM_ON_EDGE,
187+};
188+
189+/**
190+ * dim_on_top - check if current state is a good place to stop (top location)
191+ * @dim: DIM context
192+ *
193+ * Check if current profile is a good place to park at.
194+ * This will result in reducing the DIM checks frequency as we assume we
195+ * shouldn't probably change profiles, unless traffic pattern wasn't changed.
196+ */
197+bool dim_on_top(struct dim *dim);
198+
199+/**
200+ * dim_turn - change profile alterning direction
201+ * @dim: DIM context
202+ *
203+ * Go left if we were going right and vice-versa.
204+ * Do nothing if currently parking.
205+ */
206+void dim_turn(struct dim *dim);
207+
208+/**
209+ * dim_park_on_top - enter a parking state on a top location
210+ * @dim: DIM context
211+ *
212+ * Enter parking state.
213+ * Clear all movement history.
214+ */
215+void dim_park_on_top(struct dim *dim);
216+
217+/**
218+ * dim_park_tired - enter a tired parking state
219+ * @dim: DIM context
220+ *
221+ * Enter parking state.
222+ * Clear all movement history and cause DIM checks frequency to reduce.
223+ */
224+void dim_park_tired(struct dim *dim);
225+
226+/**
227+ * dim_calc_stats - calculate the difference between two samples
228+ * @start: start sample
229+ * @end: end sample
230+ * @curr_stats: delta between samples
231+ *
232+ * Calculate the delta between two samples (in data rates).
233+ * Takes into consideration counter wrap-around.
234+ */
235+void dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
236+ struct dim_stats *curr_stats);
237+
238+/**
239+ * dim_update_sample - set a sample's fields with give values
240+ * @event_ctr: number of events to set
241+ * @packets: number of packets to set
242+ * @bytes: number of bytes to set
243+ * @s: DIM sample
244+ */
245+static inline void
246+dim_update_sample(u16 event_ctr, u64 packets, u64 bytes, struct dim_sample *s)
247+{
248+ s->time = ktime_get();
249+ s->pkt_ctr = packets;
250+ s->byte_ctr = bytes;
251+ s->event_ctr = event_ctr;
252+}
253+
254+/**
255+ * dim_update_sample_with_comps - set a sample's fields with given
256+ * values including the completion parameter
257+ * @event_ctr: number of events to set
258+ * @packets: number of packets to set
259+ * @bytes: number of bytes to set
260+ * @comps: number of completions to set
261+ * @s: DIM sample
262+ */
263+static inline void
264+dim_update_sample_with_comps(u16 event_ctr, u64 packets, u64 bytes, u64 comps,
265+ struct dim_sample *s)
266+{
267+ dim_update_sample(event_ctr, packets, bytes, s);
268+ s->comp_ctr = comps;
269+}
270+
271+/* Net DIM */
272+
273+/*
274+ * Net DIM profiles:
275+ * There are different set of profiles for each CQ period mode.
276+ * There are different set of profiles for RX/TX CQs.
277+ * Each profile size must be of NET_DIM_PARAMS_NUM_PROFILES
278+ */
279+#define NET_DIM_PARAMS_NUM_PROFILES 5
280+#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
281+#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
282+#define NET_DIM_DEF_PROFILE_CQE 1
283+#define NET_DIM_DEF_PROFILE_EQE 1
284+
285+#define NET_DIM_RX_EQE_PROFILES { \
286+ {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
287+ {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
288+ {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
289+ {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
290+ {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
291+}
292+
293+#define NET_DIM_RX_CQE_PROFILES { \
294+ {2, 256}, \
295+ {8, 128}, \
296+ {16, 64}, \
297+ {32, 64}, \
298+ {64, 64} \
299+}
300+
301+#define NET_DIM_TX_EQE_PROFILES { \
302+ {1, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
303+ {8, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
304+ {32, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
305+ {64, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
306+ {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE} \
307+}
308+
309+#define NET_DIM_TX_CQE_PROFILES { \
310+ {5, 128}, \
311+ {8, 64}, \
312+ {16, 32}, \
313+ {32, 32}, \
314+ {64, 32} \
315+}
316+
317+static const struct dim_cq_moder
318+rx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
319+ NET_DIM_RX_EQE_PROFILES,
320+ NET_DIM_RX_CQE_PROFILES,
321+};
322+
323+static const struct dim_cq_moder
324+tx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
325+ NET_DIM_TX_EQE_PROFILES,
326+ NET_DIM_TX_CQE_PROFILES,
327+};
328+
329+/**
330+ * net_dim_get_rx_moderation - provide a CQ moderation object for the given RX profile
331+ * @cq_period_mode: CQ period mode
332+ * @ix: Profile index
333+ */
334+struct dim_cq_moder net_dim_get_rx_moderation(u8 cq_period_mode, int ix);
335+
336+/**
337+ * net_dim_get_def_rx_moderation - provide the default RX moderation
338+ * @cq_period_mode: CQ period mode
339+ */
340+struct dim_cq_moder net_dim_get_def_rx_moderation(u8 cq_period_mode);
341+
342+/**
343+ * net_dim_get_tx_moderation - provide a CQ moderation object for the given TX profile
344+ * @cq_period_mode: CQ period mode
345+ * @ix: Profile index
346+ */
347+struct dim_cq_moder net_dim_get_tx_moderation(u8 cq_period_mode, int ix);
348+
349+/**
350+ * net_dim_get_def_tx_moderation - provide the default TX moderation
351+ * @cq_period_mode: CQ period mode
352+ */
353+struct dim_cq_moder net_dim_get_def_tx_moderation(u8 cq_period_mode);
354+
355+/**
356+ * net_dim - main DIM algorithm entry point
357+ * @dim: DIM instance information
358+ * @end_sample: Current data measurement
359+ *
360+ * Called by the consumer.
361+ * This is the main logic of the algorithm, where data is processed in order to decide on next
362+ * required action.
363+ */
364+void net_dim(struct dim *dim, struct dim_sample end_sample);
365+
366+#endif /* DIM_H */
include/linux/net_dim.h+0−418
@@ -1,418 +0,0 @@
1−/*
2− * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3− * Copyright (c) 2017-2018, Broadcom Limited. All rights reserved.
4− *
5− * This software is available to you under a choice of one of two
6− * licenses. You may choose to be licensed under the terms of the GNU
7− * General Public License (GPL) Version 2, available from the file
8− * COPYING in the main directory of this source tree, or the
9− * OpenIB.org BSD license below:
10− *
11− * Redistribution and use in source and binary forms, with or
12− * without modification, are permitted provided that the following
13− * conditions are met:
14− *
15− * - Redistributions of source code must retain the above
16− * copyright notice, this list of conditions and the following
17− * disclaimer.
18− *
19− * - Redistributions in binary form must reproduce the above
20− * copyright notice, this list of conditions and the following
21− * disclaimer in the documentation and/or other materials
22− * provided with the distribution.
23− *
24− * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25− * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26− * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27− * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28− * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29− * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30− * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31− * SOFTWARE.
32− */
33−
34−#ifndef NET_DIM_H
35−#define NET_DIM_H
36−
37−#include <linux/module.h>
38−
39−struct net_dim_cq_moder {
40− u16 usec;
41− u16 pkts;
42− u8 cq_period_mode;
43−};
44−
45−struct net_dim_sample {
46− ktime_t time;
47− u32 pkt_ctr;
48− u32 byte_ctr;
49− u16 event_ctr;
50−};
51−
52−struct net_dim_stats {
53− int ppms; /* packets per msec */
54− int bpms; /* bytes per msec */
55− int epms; /* events per msec */
56−};
57−
58−struct net_dim { /* Adaptive Moderation */
59− u8 state;
60− struct net_dim_stats prev_stats;
61− struct net_dim_sample start_sample;
62− struct work_struct work;
63− u8 profile_ix;
64− u8 mode;
65− u8 tune_state;
66− u8 steps_right;
67− u8 steps_left;
68− u8 tired;
69−};
70−
71−enum {
72− NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
73− NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
74− NET_DIM_CQ_PERIOD_NUM_MODES
75−};
76−
77−/* Adaptive moderation logic */
78−enum {
79− NET_DIM_START_MEASURE,
80− NET_DIM_MEASURE_IN_PROGRESS,
81− NET_DIM_APPLY_NEW_PROFILE,
82−};
83−
84−enum {
85− NET_DIM_PARKING_ON_TOP,
86− NET_DIM_PARKING_TIRED,
87− NET_DIM_GOING_RIGHT,
88− NET_DIM_GOING_LEFT,
89−};
90−
91−enum {
92− NET_DIM_STATS_WORSE,
93− NET_DIM_STATS_SAME,
94− NET_DIM_STATS_BETTER,
95−};
96−
97−enum {
98− NET_DIM_STEPPED,
99− NET_DIM_TOO_TIRED,
100− NET_DIM_ON_EDGE,
101−};
102−
103−#define NET_DIM_PARAMS_NUM_PROFILES 5
104−/* Adaptive moderation profiles */
105−#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
106−#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
107−#define NET_DIM_DEF_PROFILE_CQE 1
108−#define NET_DIM_DEF_PROFILE_EQE 1
109−
110−/* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
111−#define NET_DIM_RX_EQE_PROFILES { \
112− {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
113− {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
114− {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
115− {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
116− {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
117−}
118−
119−#define NET_DIM_RX_CQE_PROFILES { \
120− {2, 256}, \
121− {8, 128}, \
122− {16, 64}, \
123− {32, 64}, \
124− {64, 64} \
125−}
126−
127−#define NET_DIM_TX_EQE_PROFILES { \
128− {1, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
129− {8, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
130− {32, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
131− {64, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
132− {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE} \
133−}
134−
135−#define NET_DIM_TX_CQE_PROFILES { \
136− {5, 128}, \
137− {8, 64}, \
138− {16, 32}, \
139− {32, 32}, \
140− {64, 32} \
141−}
142−
143−static const struct net_dim_cq_moder
144−rx_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
145− NET_DIM_RX_EQE_PROFILES,
146− NET_DIM_RX_CQE_PROFILES,
147−};
148−
149−static const struct net_dim_cq_moder
150−tx_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
151− NET_DIM_TX_EQE_PROFILES,
152− NET_DIM_TX_CQE_PROFILES,
153−};
154−
155−static inline struct net_dim_cq_moder
156−net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
157−{
158− struct net_dim_cq_moder cq_moder = rx_profile[cq_period_mode][ix];
159−
160− cq_moder.cq_period_mode = cq_period_mode;
161− return cq_moder;
162−}
163−
164−static inline struct net_dim_cq_moder
165−net_dim_get_def_rx_moderation(u8 cq_period_mode)
166−{
167− u8 profile_ix = cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
168− NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
169−
170− return net_dim_get_rx_moderation(cq_period_mode, profile_ix);
171−}
172−
173−static inline struct net_dim_cq_moder
174−net_dim_get_tx_moderation(u8 cq_period_mode, int ix)
175−{
176− struct net_dim_cq_moder cq_moder = tx_profile[cq_period_mode][ix];
177−
178− cq_moder.cq_period_mode = cq_period_mode;
179− return cq_moder;
180−}
181−
182−static inline struct net_dim_cq_moder
183−net_dim_get_def_tx_moderation(u8 cq_period_mode)
184−{
185− u8 profile_ix = cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
186− NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
187−
188− return net_dim_get_tx_moderation(cq_period_mode, profile_ix);
189−}
190−
191−static inline bool net_dim_on_top(struct net_dim *dim)
192−{
193− switch (dim->tune_state) {
194− case NET_DIM_PARKING_ON_TOP:
195− case NET_DIM_PARKING_TIRED:
196− return true;
197− case NET_DIM_GOING_RIGHT:
198− return (dim->steps_left > 1) && (dim->steps_right == 1);
199− default: /* NET_DIM_GOING_LEFT */
200− return (dim->steps_right > 1) && (dim->steps_left == 1);
201− }
202−}
203−
204−static inline void net_dim_turn(struct net_dim *dim)
205−{
206− switch (dim->tune_state) {
207− case NET_DIM_PARKING_ON_TOP:
208− case NET_DIM_PARKING_TIRED:
209− break;
210− case NET_DIM_GOING_RIGHT:
211− dim->tune_state = NET_DIM_GOING_LEFT;
212− dim->steps_left = 0;
213− break;
214− case NET_DIM_GOING_LEFT:
215− dim->tune_state = NET_DIM_GOING_RIGHT;
216− dim->steps_right = 0;
217− break;
218− }
219−}
220−
221−static inline int net_dim_step(struct net_dim *dim)
222−{
223− if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
224− return NET_DIM_TOO_TIRED;
225−
226− switch (dim->tune_state) {
227− case NET_DIM_PARKING_ON_TOP:
228− case NET_DIM_PARKING_TIRED:
229− break;
230− case NET_DIM_GOING_RIGHT:
231− if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
232− return NET_DIM_ON_EDGE;
233− dim->profile_ix++;
234− dim->steps_right++;
235− break;
236− case NET_DIM_GOING_LEFT:
237− if (dim->profile_ix == 0)
238− return NET_DIM_ON_EDGE;
239− dim->profile_ix--;
240− dim->steps_left++;
241− break;
242− }
243−
244− dim->tired++;
245− return NET_DIM_STEPPED;
246−}
247−
248−static inline void net_dim_park_on_top(struct net_dim *dim)
249−{
250− dim->steps_right = 0;
251− dim->steps_left = 0;
252− dim->tired = 0;
253− dim->tune_state = NET_DIM_PARKING_ON_TOP;
254−}
255−
256−static inline void net_dim_park_tired(struct net_dim *dim)
257−{
258− dim->steps_right = 0;
259− dim->steps_left = 0;
260− dim->tune_state = NET_DIM_PARKING_TIRED;
261−}
262−
263−static inline void net_dim_exit_parking(struct net_dim *dim)
264−{
265− dim->tune_state = dim->profile_ix ? NET_DIM_GOING_LEFT :
266− NET_DIM_GOING_RIGHT;
267− net_dim_step(dim);
268−}
269−
270−#define IS_SIGNIFICANT_DIFF(val, ref) \
271− (((100UL * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */
272−
273−static inline int net_dim_stats_compare(struct net_dim_stats *curr,
274− struct net_dim_stats *prev)
275−{
276− if (!prev->bpms)
277− return curr->bpms ? NET_DIM_STATS_BETTER :
278− NET_DIM_STATS_SAME;
279−
280− if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
281− return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER :
282− NET_DIM_STATS_WORSE;
283−
284− if (!prev->ppms)
285− return curr->ppms ? NET_DIM_STATS_BETTER :
286− NET_DIM_STATS_SAME;
287−
288− if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
289− return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER :
290− NET_DIM_STATS_WORSE;
291−
292− if (!prev->epms)
293− return NET_DIM_STATS_SAME;
294−
295− if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
296− return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER :
297− NET_DIM_STATS_WORSE;
298−
299− return NET_DIM_STATS_SAME;
300−}
301−
302−static inline bool net_dim_decision(struct net_dim_stats *curr_stats,
303− struct net_dim *dim)
304−{
305− int prev_state = dim->tune_state;
306− int prev_ix = dim->profile_ix;
307− int stats_res;
308− int step_res;
309−
310− switch (dim->tune_state) {
311− case NET_DIM_PARKING_ON_TOP:
312− stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
313− if (stats_res != NET_DIM_STATS_SAME)
314− net_dim_exit_parking(dim);
315− break;
316−
317− case NET_DIM_PARKING_TIRED:
318− dim->tired--;
319− if (!dim->tired)
320− net_dim_exit_parking(dim);
321− break;
322−
323− case NET_DIM_GOING_RIGHT:
324− case NET_DIM_GOING_LEFT:
325− stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
326− if (stats_res != NET_DIM_STATS_BETTER)
327− net_dim_turn(dim);
328−
329− if (net_dim_on_top(dim)) {
330− net_dim_park_on_top(dim);
331− break;
332− }
333−
334− step_res = net_dim_step(dim);
335− switch (step_res) {
336− case NET_DIM_ON_EDGE:
337− net_dim_park_on_top(dim);
338− break;
339− case NET_DIM_TOO_TIRED:
340− net_dim_park_tired(dim);
341− break;
342− }
343−
344− break;
345− }
346−
347− if ((prev_state != NET_DIM_PARKING_ON_TOP) ||
348− (dim->tune_state != NET_DIM_PARKING_ON_TOP))
349− dim->prev_stats = *curr_stats;
350−
351− return dim->profile_ix != prev_ix;
352−}
353−
354−static inline void net_dim_sample(u16 event_ctr,
355− u64 packets,
356− u64 bytes,
357− struct net_dim_sample *s)
358−{
359− s->time = ktime_get();
360− s->pkt_ctr = packets;
361− s->byte_ctr = bytes;
362− s->event_ctr = event_ctr;
363−}
364−
365−#define NET_DIM_NEVENTS 64
366−#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1))
367−
368−static inline void net_dim_calc_stats(struct net_dim_sample *start,
369− struct net_dim_sample *end,
370− struct net_dim_stats *curr_stats)
371−{
372− /* u32 holds up to 71 minutes, should be enough */
373− u32 delta_us = ktime_us_delta(end->time, start->time);
374− u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
375− u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
376− start->byte_ctr);
377−
378− if (!delta_us)
379− return;
380−
381− curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
382− curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
383− curr_stats->epms = DIV_ROUND_UP(NET_DIM_NEVENTS * USEC_PER_MSEC,
384− delta_us);
385−}
386−
387−static inline void net_dim(struct net_dim *dim,
388− struct net_dim_sample end_sample)
389−{
390− struct net_dim_stats curr_stats;
391− u16 nevents;
392−
393− switch (dim->state) {
394− case NET_DIM_MEASURE_IN_PROGRESS:
395− nevents = BIT_GAP(BITS_PER_TYPE(u16),
396− end_sample.event_ctr,
397− dim->start_sample.event_ctr);
398− if (nevents < NET_DIM_NEVENTS)
399− break;
400− net_dim_calc_stats(&dim->start_sample, &end_sample,
401− &curr_stats);
402− if (net_dim_decision(&curr_stats, dim)) {
403− dim->state = NET_DIM_APPLY_NEW_PROFILE;
404− schedule_work(&dim->work);
405− break;
406− }
407− /* fall through */
408− case NET_DIM_START_MEASURE:
409− net_dim_sample(end_sample.event_ctr, end_sample.pkt_ctr, end_sample.byte_ctr,
410− &dim->start_sample);
411− dim->state = NET_DIM_MEASURE_IN_PROGRESS;
412− break;
413− case NET_DIM_APPLY_NEW_PROFILE:
414− break;
415− }
416−}
417−
418−#endif /* NET_DIM_H */
lib/Kconfig+8−0
@@ -562,6 +562,14 @@ config SIGNATURE · 561 unmodified lines
562562 Digital signature verification. Currently only RSA is supported.
563563 Implementation is done using GnuPG MPI library
564564
565+config DIMLIB
566+ bool "DIM library"
567+ default y
568+ help
569+ Dynamic Interrupt Moderation library.
570+ Implements an algorithm for dynamically change CQ modertion values
571+ according to run time performance.
572+
565573 #
566574 # libfdt files, only selected if needed.
567575 #
lib/Makefile+1−0
@@ -202,6 +202,7 @@ obj-$(CONFIG_GLOB) += glob.o · 201 unmodified lines
202202 obj-$(CONFIG_GLOB_SELFTEST) += globtest.o
203203
204204 obj-$(CONFIG_MPILIB) += mpi/
205+obj-$(CONFIG_DIMLIB) += dim/
205206 obj-$(CONFIG_SIGNATURE) += digsig.o
206207
207208 lib-$(CONFIG_CLZ_TAB) += clz_tab.o
lib/dim/Makefile+9−0
@@ -0,0 +1,9 @@
1+#
2+# DIM Dynamic Interrupt Moderation library
3+#
4+
5+obj-$(CONFIG_DIMLIB) = net_dim.o
6+
7+net_dim-y = \
8+ dim.o \
9+ net_dim.o
lib/dim/dim.c+83−0
@@ -0,0 +1,83 @@
1+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+/*
3+ * Copyright (c) 2019, Mellanox Technologies inc. All rights reserved.
4+ */
5+
6+#include <linux/dim.h>
7+
8+bool dim_on_top(struct dim *dim)
9+{
10+ switch (dim->tune_state) {
11+ case DIM_PARKING_ON_TOP:
12+ case DIM_PARKING_TIRED:
13+ return true;
14+ case DIM_GOING_RIGHT:
15+ return (dim->steps_left > 1) && (dim->steps_right == 1);
16+ default: /* DIM_GOING_LEFT */
17+ return (dim->steps_right > 1) && (dim->steps_left == 1);
18+ }
19+}
20+EXPORT_SYMBOL(dim_on_top);
21+
22+void dim_turn(struct dim *dim)
23+{
24+ switch (dim->tune_state) {
25+ case DIM_PARKING_ON_TOP:
26+ case DIM_PARKING_TIRED:
27+ break;
28+ case DIM_GOING_RIGHT:
29+ dim->tune_state = DIM_GOING_LEFT;
30+ dim->steps_left = 0;
31+ break;
32+ case DIM_GOING_LEFT:
33+ dim->tune_state = DIM_GOING_RIGHT;
34+ dim->steps_right = 0;
35+ break;
36+ }
37+}
38+EXPORT_SYMBOL(dim_turn);
39+
40+void dim_park_on_top(struct dim *dim)
41+{
42+ dim->steps_right = 0;
43+ dim->steps_left = 0;
44+ dim->tired = 0;
45+ dim->tune_state = DIM_PARKING_ON_TOP;
46+}
47+EXPORT_SYMBOL(dim_park_on_top);
48+
49+void dim_park_tired(struct dim *dim)
50+{
51+ dim->steps_right = 0;
52+ dim->steps_left = 0;
53+ dim->tune_state = DIM_PARKING_TIRED;
54+}
55+EXPORT_SYMBOL(dim_park_tired);
56+
57+void dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
58+ struct dim_stats *curr_stats)
59+{
60+ /* u32 holds up to 71 minutes, should be enough */
61+ u32 delta_us = ktime_us_delta(end->time, start->time);
62+ u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
63+ u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
64+ start->byte_ctr);
65+ u32 ncomps = BIT_GAP(BITS_PER_TYPE(u32), end->comp_ctr,
66+ start->comp_ctr);
67+
68+ if (!delta_us)
69+ return;
70+
71+ curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
72+ curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
73+ curr_stats->epms = DIV_ROUND_UP(DIM_NEVENTS * USEC_PER_MSEC,
74+ delta_us);
75+ curr_stats->cpms = DIV_ROUND_UP(ncomps * USEC_PER_MSEC, delta_us);
76+ if (curr_stats->epms != 0)
77+ curr_stats->cpe_ratio =
78+ (curr_stats->cpms * 100) / curr_stats->epms;
79+ else
80+ curr_stats->cpe_ratio = 0;
81+
82+}
83+EXPORT_SYMBOL(dim_calc_stats);
lib/dim/net_dim.c+190−0
@@ -0,0 +1,190 @@
1+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+/*
3+ * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
4+ */
5+
6+#include <linux/dim.h>
7+
8+struct dim_cq_moder
9+net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
10+{
11+ struct dim_cq_moder cq_moder = rx_profile[cq_period_mode][ix];
12+
13+ cq_moder.cq_period_mode = cq_period_mode;
14+ return cq_moder;
15+}
16+EXPORT_SYMBOL(net_dim_get_rx_moderation);
17+
18+struct dim_cq_moder
19+net_dim_get_def_rx_moderation(u8 cq_period_mode)
20+{
21+ u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
22+ NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
23+
24+ return net_dim_get_rx_moderation(cq_period_mode, profile_ix);
25+}
26+EXPORT_SYMBOL(net_dim_get_def_rx_moderation);
27+
28+struct dim_cq_moder
29+net_dim_get_tx_moderation(u8 cq_period_mode, int ix)
30+{
31+ struct dim_cq_moder cq_moder = tx_profile[cq_period_mode][ix];
32+
33+ cq_moder.cq_period_mode = cq_period_mode;
34+ return cq_moder;
35+}
36+EXPORT_SYMBOL(net_dim_get_tx_moderation);
37+
38+struct dim_cq_moder
39+net_dim_get_def_tx_moderation(u8 cq_period_mode)
40+{
41+ u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
42+ NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
43+
44+ return net_dim_get_tx_moderation(cq_period_mode, profile_ix);
45+}
46+EXPORT_SYMBOL(net_dim_get_def_tx_moderation);
47+
48+static int net_dim_step(struct dim *dim)
49+{
50+ if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
51+ return DIM_TOO_TIRED;
52+
53+ switch (dim->tune_state) {
54+ case DIM_PARKING_ON_TOP:
55+ case DIM_PARKING_TIRED:
56+ break;
57+ case DIM_GOING_RIGHT:
58+ if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
59+ return DIM_ON_EDGE;
60+ dim->profile_ix++;
61+ dim->steps_right++;
62+ break;
63+ case DIM_GOING_LEFT:
64+ if (dim->profile_ix == 0)
65+ return DIM_ON_EDGE;
66+ dim->profile_ix--;
67+ dim->steps_left++;
68+ break;
69+ }
70+
71+ dim->tired++;
72+ return DIM_STEPPED;
73+}
74+
75+static void net_dim_exit_parking(struct dim *dim)
76+{
77+ dim->tune_state = dim->profile_ix ? DIM_GOING_LEFT : DIM_GOING_RIGHT;
78+ net_dim_step(dim);
79+}
80+
81+static int net_dim_stats_compare(struct dim_stats *curr,
82+ struct dim_stats *prev)
83+{
84+ if (!prev->bpms)
85+ return curr->bpms ? DIM_STATS_BETTER : DIM_STATS_SAME;
86+
87+ if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
88+ return (curr->bpms > prev->bpms) ? DIM_STATS_BETTER :
89+ DIM_STATS_WORSE;
90+
91+ if (!prev->ppms)
92+ return curr->ppms ? DIM_STATS_BETTER :
93+ DIM_STATS_SAME;
94+
95+ if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
96+ return (curr->ppms > prev->ppms) ? DIM_STATS_BETTER :
97+ DIM_STATS_WORSE;
98+
99+ if (!prev->epms)
100+ return DIM_STATS_SAME;
101+
102+ if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
103+ return (curr->epms < prev->epms) ? DIM_STATS_BETTER :
104+ DIM_STATS_WORSE;
105+
106+ return DIM_STATS_SAME;
107+}
108+
109+static bool net_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
110+{
111+ int prev_state = dim->tune_state;
112+ int prev_ix = dim->profile_ix;
113+ int stats_res;
114+ int step_res;
115+
116+ switch (dim->tune_state) {
117+ case DIM_PARKING_ON_TOP:
118+ stats_res = net_dim_stats_compare(curr_stats,
119+ &dim->prev_stats);
120+ if (stats_res != DIM_STATS_SAME)
121+ net_dim_exit_parking(dim);
122+ break;
123+
124+ case DIM_PARKING_TIRED:
125+ dim->tired--;
126+ if (!dim->tired)
127+ net_dim_exit_parking(dim);
128+ break;
129+
130+ case DIM_GOING_RIGHT:
131+ case DIM_GOING_LEFT:
132+ stats_res = net_dim_stats_compare(curr_stats,
133+ &dim->prev_stats);
134+ if (stats_res != DIM_STATS_BETTER)
135+ dim_turn(dim);
136+
137+ if (dim_on_top(dim)) {
138+ dim_park_on_top(dim);
139+ break;
140+ }
141+
142+ step_res = net_dim_step(dim);
143+ switch (step_res) {
144+ case DIM_ON_EDGE:
145+ dim_park_on_top(dim);
146+ break;
147+ case DIM_TOO_TIRED:
148+ dim_park_tired(dim);
149+ break;
150+ }
151+
152+ break;
153+ }
154+
155+ if (prev_state != DIM_PARKING_ON_TOP ||
156+ dim->tune_state != DIM_PARKING_ON_TOP)
157+ dim->prev_stats = *curr_stats;
158+
159+ return dim->profile_ix != prev_ix;
160+}
161+
162+void net_dim(struct dim *dim, struct dim_sample end_sample)
163+{
164+ struct dim_stats curr_stats;
165+ u16 nevents;
166+
167+ switch (dim->state) {
168+ case DIM_MEASURE_IN_PROGRESS:
169+ nevents = BIT_GAP(BITS_PER_TYPE(u16),
170+ end_sample.event_ctr,
171+ dim->start_sample.event_ctr);
172+ if (nevents < DIM_NEVENTS)
173+ break;
174+ dim_calc_stats(&dim->start_sample, &end_sample, &curr_stats);
175+ if (net_dim_decision(&curr_stats, dim)) {
176+ dim->state = DIM_APPLY_NEW_PROFILE;
177+ schedule_work(&dim->work);
178+ break;
179+ }
180+ /* fall through */
181+ case DIM_START_MEASURE:
182+ dim_update_sample(end_sample.event_ctr, end_sample.pkt_ctr,
183+ end_sample.byte_ctr, &dim->start_sample);
184+ dim->state = DIM_MEASURE_IN_PROGRESS;
185+ break;
186+ case DIM_APPLY_NEW_PROFILE:
187+ break;
188+ }
189+}
190+EXPORT_SYMBOL(net_dim);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t