#define RCB_RING_NAME_LEN 16
 
+#define HNAE_LOWEST_LATENCY_COAL_PARAM 30
+#define HNAE_LOW_LATENCY_COAL_PARAM    80
+#define HNAE_BULK_LATENCY_COAL_PARAM   150
+
 enum hnae_led_state {
        HNAE_LED_INACTIVE,
        HNAE_LED_ACTIVE,
 
        int flags;          /* ring attribute */
        int irq_init_flag;
+
+       /* total rx bytes after last rx rate calucated */
+       u64 coal_last_rx_bytes;
+       unsigned long coal_last_jiffies;
+       u32 coal_param;
+       u32 coal_rx_rate;       /* rx rate in MB */
 };
 
 #define ring_ptr_move_fw(ring, p) \
        u32 if_support;
        int q_num;
        int vf_id;
+       unsigned long coal_last_jiffies;
+       u32 coal_param;         /* self adapt coalesce param */
+       /* the ring index of last ring that set coal param */
+       u32 coal_ring_idx;
        u32 eport_id;
        u32 dport_id;   /* v2 tx bd should fill the dport_id */
+       bool coal_adapt_en;
        enum hnae_port_type port_type;
        enum hnae_media_type media_type;
        struct list_head node;    /* list to hnae_ae_dev->handle_list */
 
        return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu;
 }
 
+#define HNS_LOWEST_LATENCY_RATE                27      /* 27 MB/s */
+#define HNS_LOW_LATENCY_RATE                   80      /* 80 MB/s */
+
+#define HNS_COAL_BDNUM                 3
+
+static u32 hns_coal_rx_bdnum(struct hnae_ring *ring)
+{
+       bool coal_enable = ring->q->handle->coal_adapt_en;
+
+       if (coal_enable &&
+           ring->coal_last_rx_bytes > HNS_LOWEST_LATENCY_RATE)
+               return HNS_COAL_BDNUM;
+       else
+               return 0;
+}
+
+static void hns_update_rx_rate(struct hnae_ring *ring)
+{
+       bool coal_enable = ring->q->handle->coal_adapt_en;
+       u32 time_passed_ms;
+       u64 total_bytes;
+
+       if (!coal_enable ||
+           time_before(jiffies, ring->coal_last_jiffies + (HZ >> 4)))
+               return;
+
+       /* ring->stats.rx_bytes overflowed */
+       if (ring->coal_last_rx_bytes > ring->stats.rx_bytes) {
+               ring->coal_last_rx_bytes = ring->stats.rx_bytes;
+               ring->coal_last_jiffies = jiffies;
+               return;
+       }
+
+       total_bytes = ring->stats.rx_bytes - ring->coal_last_rx_bytes;
+       time_passed_ms = jiffies_to_msecs(jiffies - ring->coal_last_jiffies);
+       ring->coal_rx_rate = (total_bytes / time_passed_ms) >> 10;
+
+       ring->coal_last_rx_bytes = ring->stats.rx_bytes;
+       ring->coal_last_jiffies = jiffies;
+}
+
+/**
+ * smooth_alg - smoothing algrithm for adjusting coalesce parameter
+ **/
+static u32 smooth_alg(u32 new_param, u32 old_param)
+{
+       u32 gap = (new_param > old_param) ? new_param - old_param
+                                         : old_param - new_param;
+
+       if (gap > 8)
+               gap >>= 3;
+
+       if (new_param > old_param)
+               return old_param + gap;
+       else
+               return old_param - gap;
+}
+
+/**
+ * hns_nic_adp_coalesce - self adapte coalesce according to rx rate
+ * @ring_data: pointer to hns_nic_ring_data
+ **/
+static void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
+{
+       struct hnae_ring *ring = ring_data->ring;
+       struct hnae_handle *handle = ring->q->handle;
+       u32 new_coal_param, old_coal_param = ring->coal_param;
+
+       if (ring->coal_rx_rate < HNS_LOWEST_LATENCY_RATE)
+               new_coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
+       else if (ring->coal_rx_rate < HNS_LOW_LATENCY_RATE)
+               new_coal_param = HNAE_LOW_LATENCY_COAL_PARAM;
+       else
+               new_coal_param = HNAE_BULK_LATENCY_COAL_PARAM;
+
+       if (new_coal_param == old_coal_param &&
+           new_coal_param == handle->coal_param)
+               return;
+
+       new_coal_param = smooth_alg(new_coal_param, old_coal_param);
+       ring->coal_param = new_coal_param;
+
+       /**
+        * Because all ring in one port has one coalesce param, when one ring
+        * calculate its own coalesce param, it cannot write to hardware at
+        * once. There are three conditions as follows:
+        *       1. current ring's coalesce param is larger than the hardware.
+        *       2. or ring which adapt last time can change again.
+        *       3. timeout.
+        */
+       if (new_coal_param == handle->coal_param) {
+               handle->coal_last_jiffies = jiffies;
+               handle->coal_ring_idx = ring_data->queue_index;
+       } else if (new_coal_param > handle->coal_param ||
+                  handle->coal_ring_idx == ring_data->queue_index ||
+                  time_after(jiffies, handle->coal_last_jiffies + (HZ >> 4))) {
+               handle->dev->ops->set_coalesce_usecs(handle,
+                                       new_coal_param);
+               handle->dev->ops->set_coalesce_frames(handle,
+                                       1, new_coal_param);
+               handle->coal_param = new_coal_param;
+               handle->coal_ring_idx = ring_data->queue_index;
+               handle->coal_last_jiffies = jiffies;
+       }
+}
+
 static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data,
                               int budget, void *v)
 {
 {
        struct hnae_ring *ring = ring_data->ring;
        int num = 0;
+       bool rx_stopped;
 
-       ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
+       hns_update_rx_rate(ring);
 
        /* for hardware bug fixed */
+       ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
        num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
 
-       if (num > 0) {
+       if (num <= hns_coal_rx_bdnum(ring)) {
+               if (ring->q->handle->coal_adapt_en)
+                       hns_nic_adpt_coalesce(ring_data);
+
+               rx_stopped = true;
+       } else {
                ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
                        ring_data->ring, 1);
 
-               return false;
-       } else {
-               return true;
+               rx_stopped = false;
        }
+
+       return rx_stopped;
 }
 
 static bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
        struct hnae_ring *ring = ring_data->ring;
        int num;
 
+       hns_update_rx_rate(ring);
        num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
 
-       if (!num)
+       if (num <= hns_coal_rx_bdnum(ring)) {
+               if (ring->q->handle->coal_adapt_en)
+                       hns_nic_adpt_coalesce(ring_data);
+
                return true;
-       else
-               return false;
+       }
+
+       return false;
 }
 
 static inline void hns_nic_reclaim_one_desc(struct hnae_ring *ring,