* @np: net device to configure
  * @filter_dev: device on which filter is added
  * @cls_flower: offload data
+ * @ingress: if the rule is added to an ingress block
+ *
+ * Return: 0 if the flower was successfully added or deleted,
+ *        negative error code otherwise.
  */
 static int
 ice_setup_tc_cls_flower(struct ice_netdev_priv *np,
                        struct net_device *filter_dev,
-                       struct flow_cls_offload *cls_flower)
+                       struct flow_cls_offload *cls_flower,
+                       bool ingress)
 {
        struct ice_vsi *vsi = np->vsi;
 
 
        switch (cls_flower->command) {
        case FLOW_CLS_REPLACE:
-               return ice_add_cls_flower(filter_dev, vsi, cls_flower);
+               return ice_add_cls_flower(filter_dev, vsi, cls_flower, ingress);
        case FLOW_CLS_DESTROY:
                return ice_del_cls_flower(vsi, cls_flower);
        default:
 }
 
 /**
- * ice_setup_tc_block_cb - callback handler registered for TC block
+ * ice_setup_tc_block_cb_ingress - callback handler for ingress TC block
  * @type: TC SETUP type
  * @type_data: TC flower offload data that contains user input
  * @cb_priv: netdev private data
+ *
+ * Return: 0 if the setup was successful, negative error code otherwise.
  */
 static int
-ice_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
+ice_setup_tc_block_cb_ingress(enum tc_setup_type type, void *type_data,
+                             void *cb_priv)
 {
        struct ice_netdev_priv *np = cb_priv;
 
        switch (type) {
        case TC_SETUP_CLSFLOWER:
                return ice_setup_tc_cls_flower(np, np->vsi->netdev,
-                                              type_data);
+                                              type_data, true);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
+ * ice_setup_tc_block_cb_egress - callback handler for egress TC block
+ * @type: TC SETUP type
+ * @type_data: TC flower offload data that contains user input
+ * @cb_priv: netdev private data
+ *
+ * Return: 0 if the setup was successful, negative error code otherwise.
+ */
+static int
+ice_setup_tc_block_cb_egress(enum tc_setup_type type, void *type_data,
+                            void *cb_priv)
+{
+       struct ice_netdev_priv *np = cb_priv;
+
+       switch (type) {
+       case TC_SETUP_CLSFLOWER:
+               return ice_setup_tc_cls_flower(np, np->vsi->netdev,
+                                              type_data, false);
        default:
                return -EOPNOTSUPP;
        }
             void *type_data)
 {
        struct ice_netdev_priv *np = netdev_priv(netdev);
+       enum flow_block_binder_type binder_type;
        struct ice_pf *pf = np->vsi->back;
+       flow_setup_cb_t *flower_handler;
        bool locked = false;
        int err;
 
        switch (type) {
        case TC_SETUP_BLOCK:
+               binder_type =
+                       ((struct flow_block_offload *)type_data)->binder_type;
+
+               switch (binder_type) {
+               case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
+                       flower_handler = ice_setup_tc_block_cb_ingress;
+                       break;
+               case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
+                       flower_handler = ice_setup_tc_block_cb_egress;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+
                return flow_block_cb_setup_simple(type_data,
                                                  &ice_block_cb_list,
-                                                 ice_setup_tc_block_cb,
-                                                 np, np, true);
+                                                 flower_handler,
+                                                 np, np, false);
        case TC_SETUP_QDISC_MQPRIO:
                if (ice_is_eswitch_mode_switchdev(pf)) {
                        netdev_err(netdev, "TC MQPRIO offload not supported, switchdev is enabled\n");
        case TC_SETUP_CLSFLOWER:
                return ice_setup_tc_cls_flower(np, priv->netdev,
                                               (struct flow_cls_offload *)
-                                              type_data);
+                                              type_data, false);
        default:
                return -EOPNOTSUPP;
        }
 
        fltr->action.fltr_act = action;
 
        if (ice_is_port_repr_netdev(filter_dev) &&
-           ice_is_port_repr_netdev(target_dev)) {
+           ice_is_port_repr_netdev(target_dev) &&
+           fltr->direction == ICE_ESWITCH_FLTR_EGRESS) {
                repr = ice_netdev_to_repr(target_dev);
 
                fltr->dest_vsi = repr->src_vsi;
-               fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
        } else if (ice_is_port_repr_netdev(filter_dev) &&
-                  ice_tc_is_dev_uplink(target_dev)) {
+                  ice_tc_is_dev_uplink(target_dev) &&
+                  fltr->direction == ICE_ESWITCH_FLTR_EGRESS) {
                repr = ice_netdev_to_repr(filter_dev);
 
                fltr->dest_vsi = repr->src_vsi->back->eswitch.uplink_vsi;
-               fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
        } else if (ice_tc_is_dev_uplink(filter_dev) &&
-                  ice_is_port_repr_netdev(target_dev)) {
+                  ice_is_port_repr_netdev(target_dev) &&
+                  fltr->direction == ICE_ESWITCH_FLTR_INGRESS) {
                repr = ice_netdev_to_repr(target_dev);
 
                fltr->dest_vsi = repr->src_vsi;
-               fltr->direction = ICE_ESWITCH_FLTR_INGRESS;
        } else {
                NL_SET_ERR_MSG_MOD(fltr->extack,
-                                  "Unsupported netdevice in switchdev mode");
+                                  "The action is not supported for this netdevice");
                return -EINVAL;
        }
 
 {
        fltr->action.fltr_act = ICE_DROP_PACKET;
 
-       if (ice_is_port_repr_netdev(filter_dev)) {
-               fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
-       } else if (ice_tc_is_dev_uplink(filter_dev)) {
-               fltr->direction = ICE_ESWITCH_FLTR_INGRESS;
-       } else {
+       if (!ice_tc_is_dev_uplink(filter_dev) &&
+           !(ice_is_port_repr_netdev(filter_dev) &&
+             fltr->direction == ICE_ESWITCH_FLTR_INGRESS)) {
                NL_SET_ERR_MSG_MOD(fltr->extack,
-                                  "Unsupported netdevice in switchdev mode");
+                                  "The action is not supported for this netdevice");
                return -EINVAL;
        }
 
                rule_info.sw_act.flag |= ICE_FLTR_RX;
                rule_info.sw_act.src = hw->pf_id;
                rule_info.flags_info.act = ICE_SINGLE_ACT_LB_ENABLE;
+       } else if (fltr->direction == ICE_ESWITCH_FLTR_EGRESS &&
+                  !fltr->dest_vsi && vsi == vsi->back->eswitch.uplink_vsi) {
+               /* PF to Uplink */
+               rule_info.sw_act.flag |= ICE_FLTR_TX;
+               rule_info.sw_act.src = vsi->idx;
        } else if (fltr->direction == ICE_ESWITCH_FLTR_EGRESS &&
                   fltr->dest_vsi == vsi->back->eswitch.uplink_vsi) {
                /* VF to Uplink */
                        tc_fltr->action.fwd.q.hw_queue, lkups_cnt);
                break;
        case ICE_DROP_PACKET:
-               rule_info.sw_act.flag |= ICE_FLTR_RX;
-               rule_info.sw_act.src = hw->pf_id;
+               if (tc_fltr->direction == ICE_ESWITCH_FLTR_EGRESS) {
+                       rule_info.sw_act.flag |= ICE_FLTR_TX;
+                       rule_info.sw_act.src = vsi->idx;
+               } else {
+                       rule_info.sw_act.flag |= ICE_FLTR_RX;
+                       rule_info.sw_act.src = hw->pf_id;
+               }
                rule_info.priority = ICE_SWITCH_FLTR_PRIO_VSI;
                break;
        default:
  * @filter_dev: Pointer to device on which filter is being added
  * @f: Pointer to struct flow_cls_offload
  * @fltr: Pointer to filter structure
+ * @ingress: if the rule is added to an ingress block
+ *
+ * Return: 0 if the flower was parsed successfully, -EINVAL if the flower
+ *        cannot be parsed, -EOPNOTSUPP if such filter cannot be configured
+ *        for the given VSI.
  */
 static int
 ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
                     struct flow_cls_offload *f,
-                    struct ice_tc_flower_fltr *fltr)
+                    struct ice_tc_flower_fltr *fltr, bool ingress)
 {
        struct ice_tc_flower_lyr_2_4_hdrs *headers = &fltr->outer_headers;
        struct flow_rule *rule = flow_cls_offload_flow_rule(f);
                        fltr->flags |= ICE_TC_FLWR_FIELD_ETH_TYPE_ID;
                }
 
+               if (!ingress) {
+                       bool switchdev =
+                               ice_is_eswitch_mode_switchdev(vsi->back);
+
+                       if (switchdev != (n_proto_key == ETH_P_LLDP)) {
+                               NL_SET_ERR_MSG_FMT_MOD(fltr->extack,
+                                                      "%sLLDP filtering is not supported on egress in %s mode",
+                                                      switchdev ? "Non-" : "",
+                                                      switchdev ? "switchdev" :
+                                                                  "legacy");
+                               return -EOPNOTSUPP;
+                       }
+               }
+
                headers->l2_key.n_proto = cpu_to_be16(n_proto_key);
                headers->l2_mask.n_proto = cpu_to_be16(n_proto_mask);
                headers->l3_key.ip_proto = match.key->ip_proto;
                        return -EINVAL;
                }
        }
+
+       /* Ingress filter on representor results in an egress filter in HW
+        * and vice versa
+        */
+       ingress = ice_is_port_repr_netdev(filter_dev) ? !ingress : ingress;
+       fltr->direction = ingress ? ICE_ESWITCH_FLTR_INGRESS :
+                                   ICE_ESWITCH_FLTR_EGRESS;
+
        return 0;
 }
 
  * @vsi: Pointer to VSI
  * @f: Pointer to flower offload structure
  * @__fltr: Pointer to struct ice_tc_flower_fltr
+ * @ingress: if the rule is added to an ingress block
  *
  * This function parses TC-flower input fields, parses action,
  * and adds a filter.
+ *
+ * Return: 0 if the filter was successfully added,
+ *        negative error code otherwise.
  */
 static int
 ice_add_tc_fltr(struct net_device *netdev, struct ice_vsi *vsi,
                struct flow_cls_offload *f,
-               struct ice_tc_flower_fltr **__fltr)
+               struct ice_tc_flower_fltr **__fltr, bool ingress)
 {
        struct ice_tc_flower_fltr *fltr;
        int err;
        fltr->src_vsi = vsi;
        INIT_HLIST_NODE(&fltr->tc_flower_node);
 
-       err = ice_parse_cls_flower(netdev, vsi, f, fltr);
+       err = ice_parse_cls_flower(netdev, vsi, f, fltr, ingress);
        if (err < 0)
                goto err;
 
  * @netdev: Pointer to filter device
  * @vsi: Pointer to VSI
  * @cls_flower: Pointer to flower offload structure
+ * @ingress: if the rule is added to an ingress block
+ *
+ * Return: 0 if the flower was successfully added,
+ *        negative error code otherwise.
  */
-int
-ice_add_cls_flower(struct net_device *netdev, struct ice_vsi *vsi,
-                  struct flow_cls_offload *cls_flower)
+int ice_add_cls_flower(struct net_device *netdev, struct ice_vsi *vsi,
+                      struct flow_cls_offload *cls_flower, bool ingress)
 {
        struct netlink_ext_ack *extack = cls_flower->common.extack;
        struct net_device *vsi_netdev = vsi->netdev;
        }
 
        /* prep and add TC-flower filter in HW */
-       err = ice_add_tc_fltr(netdev, vsi, cls_flower, &fltr);
+       err = ice_add_tc_fltr(netdev, vsi, cls_flower, &fltr, ingress);
        if (err)
                return err;
 
 
 
        /* allow CONTROL frames egress from main VSI if FW LLDP disabled */
        eth = (struct ethhdr *)skb_mac_header(skb);
-       if (unlikely((skb->priority == TC_PRIO_CONTROL ||
-                     eth->h_proto == htons(ETH_P_LLDP)) &&
-                    vsi->type == ICE_VSI_PF &&
-                    vsi->port_info->qos_cfg.is_sw_lldp))
-               offload.cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
-                                       ICE_TX_CTX_DESC_SWTCH_UPLINK <<
-                                       ICE_TXD_CTX_QW1_CMD_S);
 
-       ice_tstamp(tx_ring, skb, first, &offload);
        if ((ice_is_switchdev_running(vsi->back) ||
             ice_lag_is_switchdev_running(vsi->back)) &&
            vsi->type != ICE_VSI_SF)
                ice_eswitch_set_target_vsi(skb, &offload);
+       else if (unlikely((skb->priority == TC_PRIO_CONTROL ||
+                          eth->h_proto == htons(ETH_P_LLDP)) &&
+                          vsi->type == ICE_VSI_PF &&
+                          vsi->port_info->qos_cfg.is_sw_lldp))
+               offload.cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
+                                       ICE_TX_CTX_DESC_SWTCH_UPLINK <<
+                                       ICE_TXD_CTX_QW1_CMD_S);
+
+       ice_tstamp(tx_ring, skb, first, &offload);
 
        if (offload.cd_qw1 & ICE_TX_DESC_DTYPE_CTX) {
                struct ice_tx_ctx_desc *cdesc;