#include <net/busy_poll.h>
 #include <net/ip6_checksum.h>
 #include <net/page_pool.h>
+#include <net/inet_ecn.h>
 #include "en.h"
 #include "en_tc.h"
 #include "eswitch.h"
        skb_set_hash(skb, be32_to_cpu(cqe->rss_hash_result), ht);
 }
 
-static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth)
+static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth,
+                                       __be16 *proto)
 {
-       __be16 ethertype = ((struct ethhdr *)skb->data)->h_proto;
+       *proto = ((struct ethhdr *)skb->data)->h_proto;
+       *proto = __vlan_get_protocol(skb, *proto, network_depth);
+       return (*proto == htons(ETH_P_IP) || *proto == htons(ETH_P_IPV6));
+}
+
+static inline void mlx5e_enable_ecn(struct mlx5e_rq *rq, struct sk_buff *skb)
+{
+       int network_depth = 0;
+       __be16 proto;
+       void *ip;
+       int rc;
 
-       ethertype = __vlan_get_protocol(skb, ethertype, network_depth);
-       return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6));
+       if (unlikely(!is_last_ethertype_ip(skb, &network_depth, &proto)))
+               return;
+
+       ip = skb->data + network_depth;
+       rc = ((proto == htons(ETH_P_IP)) ? IP_ECN_set_ce((struct iphdr *)ip) :
+                                        IP6_ECN_set_ce(skb, (struct ipv6hdr *)ip));
+
+       rq->stats->ecn_mark += !!rc;
 }
 
 static __be32 mlx5e_get_fcs(struct sk_buff *skb)
 {
        struct mlx5e_rq_stats *stats = rq->stats;
        int network_depth = 0;
+       __be16 proto;
 
        if (unlikely(!(netdev->features & NETIF_F_RXCSUM)))
                goto csum_none;
                return;
        }
 
-       if (likely(is_last_ethertype_ip(skb, &network_depth))) {
+       if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) {
                skb->ip_summed = CHECKSUM_COMPLETE;
                skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
                if (network_depth > ETH_HLEN)
        stats->csum_none++;
 }
 
+#define MLX5E_CE_BIT_MASK 0x80
+
 static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
                                      u32 cqe_bcnt,
                                      struct mlx5e_rq *rq,
        skb->mark = be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK;
 
        mlx5e_handle_csum(netdev, cqe, rq, skb, !!lro_num_seg);
+       /* checking CE bit in cqe - MSB in ml_path field */
+       if (unlikely(cqe->ml_path & MLX5E_CE_BIT_MASK))
+               mlx5e_enable_ecn(rq, skb);
+
        skb->protocol = eth_type_trans(skb, netdev);
 }
 
 
 
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_ecn_mark) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_removed_vlan_packets) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) },
        { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) },
                s->rx_bytes     += rq_stats->bytes;
                s->rx_lro_packets += rq_stats->lro_packets;
                s->rx_lro_bytes += rq_stats->lro_bytes;
+               s->rx_ecn_mark  += rq_stats->ecn_mark;
                s->rx_removed_vlan_packets += rq_stats->removed_vlan_packets;
                s->rx_csum_none += rq_stats->csum_none;
                s->rx_csum_complete += rq_stats->csum_complete;
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, xdp_redirect) },
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_packets) },
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_bytes) },
+       { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, ecn_mark) },
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, removed_vlan_packets) },
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, wqe_err) },
        { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, mpwqe_filler_cqes) },