#define MTK_ETHTOOL_STAT(x) { #x, \
                              offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
 
+#define MTK_ETHTOOL_XDP_STAT(x) { #x, \
+                                 offsetof(struct mtk_hw_stats, xdp_stats.x) / \
+                                 sizeof(u64) }
+
 static const struct mtk_reg_map mtk_reg_map = {
        .tx_irq_mask            = 0x1a1c,
        .tx_irq_status          = 0x1a18,
        MTK_ETHTOOL_STAT(rx_long_errors),
        MTK_ETHTOOL_STAT(rx_checksum_errors),
        MTK_ETHTOOL_STAT(rx_flow_control_packets),
+       MTK_ETHTOOL_XDP_STAT(rx_xdp_redirect),
+       MTK_ETHTOOL_XDP_STAT(rx_xdp_pass),
+       MTK_ETHTOOL_XDP_STAT(rx_xdp_drop),
+       MTK_ETHTOOL_XDP_STAT(rx_xdp_tx),
+       MTK_ETHTOOL_XDP_STAT(rx_xdp_tx_errors),
+       MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit),
+       MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit_errors),
 };
 
 static const char * const mtk_clks_source_name[] = {
 static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring,
                       struct xdp_buff *xdp, struct net_device *dev)
 {
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_hw_stats *hw_stats = mac->hw_stats;
+       u64 *count = &hw_stats->xdp_stats.rx_xdp_drop;
        struct bpf_prog *prog;
        u32 act = XDP_PASS;
 
        act = bpf_prog_run_xdp(prog, xdp);
        switch (act) {
        case XDP_PASS:
-               goto out;
+               count = &hw_stats->xdp_stats.rx_xdp_pass;
+               goto update_stats;
        case XDP_REDIRECT:
                if (unlikely(xdp_do_redirect(dev, xdp, prog))) {
                        act = XDP_DROP;
                        break;
                }
-               goto out;
+
+               count = &hw_stats->xdp_stats.rx_xdp_redirect;
+               goto update_stats;
        default:
                bpf_warn_invalid_xdp_action(dev, prog, act);
                fallthrough;
 
        page_pool_put_full_page(ring->page_pool,
                                virt_to_head_page(xdp->data), true);
+
+update_stats:
+       u64_stats_update_begin(&hw_stats->syncp);
+       *count = *count + 1;
+       u64_stats_update_end(&hw_stats->syncp);
 out:
        rcu_read_unlock();