static int bnxt_tc_parse_actions(struct bnxt *bp,
                                 struct bnxt_tc_actions *actions,
-                                struct flow_action *flow_action)
+                                struct flow_action *flow_action,
+                                struct netlink_ext_ack *extack)
 {
        /* Used to store the L2 rewrite mask for dmac (6 bytes) followed by
         * smac (6 bytes) if rewrite of both is specified, otherwise either
                return -EINVAL;
        }
 
+       if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_DROP:
                flow->tun_mask.tp_src = match.mask->src;
        }
 
-       return bnxt_tc_parse_actions(bp, &flow->actions, &rule->action);
+       return bnxt_tc_parse_actions(bp, &flow->actions, &rule->action,
+                                    tc_flow_cmd->common.extack);
 }
 
 static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
 
 }
 
 int cxgb4_validate_flow_actions(struct net_device *dev,
-                               struct flow_action *actions)
+                               struct flow_action *actions,
+                               struct netlink_ext_ack *extack)
 {
        struct flow_action_entry *act;
        bool act_redir = false;
        bool act_vlan = false;
        int i;
 
+       if (!flow_action_basic_hw_stats_types_check(actions, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, actions) {
                switch (act->id) {
                case FLOW_ACTION_ACCEPT:
        struct filter_ctx ctx;
        int fidx, ret;
 
-       if (cxgb4_validate_flow_actions(dev, &rule->action))
+       if (cxgb4_validate_flow_actions(dev, &rule->action, extack))
                return -EOPNOTSUPP;
 
        if (cxgb4_validate_flow_match(dev, cls))
 
                                struct flow_action *actions,
                                struct ch_filter_specification *fs);
 int cxgb4_validate_flow_actions(struct net_device *dev,
-                               struct flow_action *actions);
+                               struct flow_action *actions,
+                               struct netlink_ext_ack *extack);
 
 int cxgb4_tc_flower_replace(struct net_device *dev,
                            struct flow_cls_offload *cls);
 
                }
 
                ret = cxgb4_validate_flow_actions(dev,
-                                                 &cls_matchall->rule->action);
+                                                 &cls_matchall->rule->action,
+                                                 extack);
                if (ret)
                        return ret;
 
 
        u8 qh, ql, pmap;
        int index, ctx;
 
+       if (!flow_action_basic_hw_stats_types_check(&rule->flow->action, NULL))
+               return -EOPNOTSUPP;
+
        memset(&c2, 0, sizeof(c2));
 
        index = mvpp2_cls_c2_port_flow_index(port, rule->loc);
        struct flow_rule *flow = rule->flow;
        struct flow_action_entry *act;
 
+       if (!flow_action_basic_hw_stats_types_check(&rule->flow->action, NULL))
+               return -EOPNOTSUPP;
+
        act = &flow->action.entries[0];
        if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
                return -EOPNOTSUPP;
 
        if (!flow_action_has_entries(flow_action))
                return -EINVAL;
 
+       if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
+               return -EOPNOTSUPP;
+
        attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
 
        flow_action_for_each(i, act, flow_action) {
        if (!flow_action_has_entries(flow_action))
                return -EINVAL;
 
+       if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_DROP:
                return -EOPNOTSUPP;
        }
 
+       if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
 
        if (!flow_offload_has_one_action(&f->rule->action))
                return -EOPNOTSUPP;
 
+       if (!flow_action_basic_hw_stats_types_check(&f->rule->action,
+                                                   f->common.extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, a, &f->rule->action) {
                switch (a->id) {
                case FLOW_ACTION_DROP:
 
        bool pkt_host = false;
        u32 csum_updated = 0;
 
+       if (!flow_action_basic_hw_stats_types_check(&flow->rule->action,
+                                                   extack))
+               return -EOPNOTSUPP;
+
        memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
        nfp_flow->meta.act_len = 0;
        tun_type = NFP_FL_TUNNEL_NONE;
 
 }
 
 static int qede_parse_actions(struct qede_dev *edev,
-                             struct flow_action *flow_action)
+                             struct flow_action *flow_action,
+                             struct netlink_ext_ack *extack)
 {
        const struct flow_action_entry *act;
        int i;
                return -EINVAL;
        }
 
+       if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_DROP:
        }
 
        /* parse tc actions and get the vf_id */
-       if (qede_parse_actions(edev, &f->rule->action))
+       if (qede_parse_actions(edev, &f->rule->action, f->common.extack))
                goto unlock;
 
        if (qede_flow_find_fltr(edev, &t)) {
                return -EINVAL;
        }
 
-       if (qede_parse_actions(edev, flow_action))
+       if (qede_parse_actions(edev, flow_action, NULL))
                return -EINVAL;
 
        return 0;
 
 
 static int tc_parse_flow_actions(struct stmmac_priv *priv,
                                 struct flow_action *action,
-                                struct stmmac_flow_entry *entry)
+                                struct stmmac_flow_entry *entry,
+                                struct netlink_ext_ack *extack)
 {
        struct flow_action_entry *act;
        int i;
        if (!flow_action_has_entries(action))
                return -EINVAL;
 
+       if (!flow_action_basic_hw_stats_types_check(action, extack))
+               return -EOPNOTSUPP;
+
        flow_action_for_each(i, act, action) {
                switch (act->id) {
                case FLOW_ACTION_DROP:
                        return -ENOENT;
        }
 
-       ret = tc_parse_flow_actions(priv, &rule->action, entry);
+       ret = tc_parse_flow_actions(priv, &rule->action, entry,
+                                   cls->common.extack);
        if (ret)
                return ret;
 
 
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/netlink.h>
 #include <net/flow_dissector.h>
 #include <linux/rhashtable.h>
 
        return action->num_entries == 1;
 }
 
+static inline bool
+flow_action_mixed_hw_stats_types_check(const struct flow_action *action,
+                                      struct netlink_ext_ack *extack)
+{
+       const struct flow_action_entry *action_entry;
+       u8 uninitialized_var(last_hw_stats_type);
+       int i;
+
+       if (flow_offload_has_one_action(action))
+               return true;
+
+       for (i = 0; i < action->num_entries; i++) {
+               action_entry = &action->entries[i];
+               if (i && action_entry->hw_stats_type != last_hw_stats_type) {
+                       NL_SET_ERR_MSG_MOD(extack, "Mixing HW stats types for actions is not supported");
+                       return false;
+               }
+               last_hw_stats_type = action_entry->hw_stats_type;
+       }
+       return true;
+}
+
+static inline const struct flow_action_entry *
+flow_action_first_entry_get(const struct flow_action *action)
+{
+       WARN_ON(!flow_action_has_entries(action));
+       return &action->entries[0];
+}
+
+static inline bool
+flow_action_hw_stats_types_check(const struct flow_action *action,
+                                struct netlink_ext_ack *extack,
+                                u8 allowed_hw_stats_type)
+{
+       const struct flow_action_entry *action_entry;
+
+       if (!flow_action_has_entries(action))
+               return true;
+       if (!flow_action_mixed_hw_stats_types_check(action, extack))
+               return false;
+       action_entry = flow_action_first_entry_get(action);
+       if (allowed_hw_stats_type == 0 &&
+           action_entry->hw_stats_type != FLOW_ACTION_HW_STATS_TYPE_ANY) {
+               NL_SET_ERR_MSG_MOD(extack, "Driver supports only default HW stats type \"any\"");
+               return false;
+       } else if (allowed_hw_stats_type != 0 &&
+                  action_entry->hw_stats_type != allowed_hw_stats_type) {
+               NL_SET_ERR_MSG_MOD(extack, "Driver does not support selected HW stats type");
+               return false;
+       }
+       return true;
+}
+
+static inline bool
+flow_action_basic_hw_stats_types_check(const struct flow_action *action,
+                                      struct netlink_ext_ack *extack)
+{
+       return flow_action_hw_stats_types_check(action, extack, 0);
+}
+
 #define flow_action_for_each(__i, __act, __actions)                    \
         for (__i = 0, __act = &(__actions)->entries[0]; __i < (__actions)->num_entries; __act = &(__actions)->entries[++__i])
 
 
        if (!flow_offload_has_one_action(&cls->rule->action))
                return err;
 
+       if (!flow_action_basic_hw_stats_types_check(&cls->rule->action,
+                                                   cls->common.extack))
+               return err;
+
        act = &cls->rule->action.entries[0];
 
        if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) {