mlx4: fix potential divide by 0 in mlx4_en_auto_moderation()
authorEric Dumazet <edumazet@google.com>
Thu, 16 Feb 2017 23:23:27 +0000 (15:23 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 19 Feb 2017 23:15:23 +0000 (18:15 -0500)
1) In the case where rate == priv->pkt_rate_low == priv->pkt_rate_high,
mlx4_en_auto_moderation() does a divide by zero.

2) We want to properly change the moderation parameters if rx_frames
was changed (like in ethtool -C eth0 rx-frames 16)

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/en_netdev.c

index 748e9f65c386b6e49ce8112cda6f47af6047cba8..afe4444e5434e915dc4221d152a0291364744e4d 100644 (file)
@@ -1382,6 +1382,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
 {
        unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies);
+       u32 pkt_rate_high, pkt_rate_low;
        struct mlx4_en_cq *cq;
        unsigned long packets;
        unsigned long rate;
@@ -1395,37 +1396,40 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
        if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ)
                return;
 
+       pkt_rate_low = READ_ONCE(priv->pkt_rate_low);
+       pkt_rate_high = READ_ONCE(priv->pkt_rate_high);
+
        for (ring = 0; ring < priv->rx_ring_num; ring++) {
                rx_packets = READ_ONCE(priv->rx_ring[ring]->packets);
                rx_bytes = READ_ONCE(priv->rx_ring[ring]->bytes);
 
-               rx_pkt_diff = ((unsigned long) (rx_packets -
-                               priv->last_moder_packets[ring]));
+               rx_pkt_diff = rx_packets - priv->last_moder_packets[ring];
                packets = rx_pkt_diff;
                rate = packets * HZ / period;
-               avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
-                               priv->last_moder_bytes[ring])) / packets : 0;
+               avg_pkt_size = packets ? (rx_bytes -
+                               priv->last_moder_bytes[ring]) / packets : 0;
 
                /* Apply auto-moderation only when packet rate
                 * exceeds a rate that it matters */
                if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) &&
                    avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) {
-                       if (rate < priv->pkt_rate_low)
+                       if (rate <pkt_rate_low)
                                moder_time = priv->rx_usecs_low;
-                       else if (rate > priv->pkt_rate_high)
+                       else if (rate >pkt_rate_high)
                                moder_time = priv->rx_usecs_high;
                        else
-                               moder_time = (rate - priv->pkt_rate_low) *
+                               moder_time = (rate - pkt_rate_low) *
                                        (priv->rx_usecs_high - priv->rx_usecs_low) /
-                                       (priv->pkt_rate_high - priv->pkt_rate_low) +
+                                       (pkt_rate_high - pkt_rate_low) +
                                        priv->rx_usecs_low;
                } else {
                        moder_time = priv->rx_usecs_low;
                }
 
-               if (moder_time != priv->last_moder_time[ring]) {
+               cq = priv->rx_cq[ring];
+               if (moder_time != priv->last_moder_time[ring] ||
+                   cq->moder_cnt != priv->rx_frames) {
                        priv->last_moder_time[ring] = moder_time;
-                       cq = priv->rx_cq[ring];
                        cq->moder_time = moder_time;
                        cq->moder_cnt = priv->rx_frames;
                        err = mlx4_en_set_cq_moder(priv, cq);