ICE_PKT_KMALLOC         = BIT(9),
        ICE_PKT_PPPOE           = BIT(10),
        ICE_PKT_L2TPV3          = BIT(11),
+       ICE_PKT_PFCP            = BIT(12),
 };
 
 struct ice_dummy_pkt_offsets {
        0x00, 0x00,
 };
 
+ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv4) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_UDP_ILOS,         34 },
+       { ICE_PFCP,             42 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv4) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x08, 0x00,             /* ICE_ETYPE_OL 12 */
+
+       0x45, 0x00, 0x00, 0x2c, /* ICE_IPV4_OFOS 14 */
+       0x00, 0x01, 0x00, 0x00,
+       0x00, 0x11, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 34 */
+       0x00, 0x18, 0x00, 0x00,
+
+       0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 42 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00,             /* 2 bytes for 4 byte alignment */
+};
+
+ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv6) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV6_OFOS,        14 },
+       { ICE_UDP_ILOS,         54 },
+       { ICE_PFCP,             62 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv6) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x86, 0xdd,             /* ICE_ETYPE_OL 12 */
+
+       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */
+       0x00, 0x10, 0x11, 0x00, /* Next header UDP */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 54 */
+       0x00, 0x18, 0x00, 0x00,
+
+       0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 62 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00,             /* 2 bytes for 4 byte alignment */
+};
+
 ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = {
        { ICE_MAC_OFOS,         0 },
        { ICE_ETYPE_OL,         12 },
        ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU),
        ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6),
        ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC),
+       ICE_PKT_PROFILE(pfcp_session_ipv6, ICE_PKT_PFCP | ICE_PKT_OUTER_IPV6),
+       ICE_PKT_PROFILE(pfcp_session_ipv4, ICE_PKT_PFCP),
        ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 |
                                        ICE_PKT_INNER_UDP),
        ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6),
        ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6),
        ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22),
        ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14),
+       ICE_PROTOCOL_ENTRY(ICE_PFCP, 8, 10, 12, 14, 16, 18, 20, 22),
        ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6),
        ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10),
        ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0),
        { ICE_NVGRE,            ICE_GRE_OF_HW },
        { ICE_GTP,              ICE_UDP_OF_HW },
        { ICE_GTP_NO_PAY,       ICE_UDP_ILOS_HW },
+       { ICE_PFCP,             ICE_UDP_ILOS_HW },
        { ICE_PPPOE,            ICE_PPPOE_HW },
        { ICE_L2TPV3,           ICE_L2TPV3_HW },
        { ICE_VLAN_EX,          ICE_VLAN_OF_HW },
        case ICE_SW_TUN_GTPC:
                prof_type = ICE_PROF_TUN_GTPC;
                break;
+       case ICE_SW_TUN_PFCP:
+               prof_type = ICE_PROF_TUN_PFCP;
+               break;
        case ICE_SW_TUN_AND_NON_TUN:
        default:
                prof_type = ICE_PROF_ALL;
        case ICE_SW_TUN_VXLAN:
                match |= ICE_PKT_TUN_UDP;
                break;
+       case ICE_SW_TUN_PFCP:
+               match |= ICE_PKT_PFCP;
+               break;
        default:
                break;
        }
                case ICE_GTP:
                        len = sizeof(struct ice_udp_gtp_hdr);
                        break;
+               case ICE_PFCP:
+                       len = sizeof(struct ice_pfcp_hdr);
+                       break;
                case ICE_PPPOE:
                        len = sizeof(struct ice_pppoe_hdr);
                        break;
 
        if (flags & ICE_TC_FLWR_FIELD_GTP_OPTS)
                lkups_cnt++;
 
+       if (flags & ICE_TC_FLWR_FIELD_PFCP_OPTS)
+               lkups_cnt++;
+
        if (flags & (ICE_TC_FLWR_FIELD_ENC_SRC_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_DEST_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_SRC_IPV6 |
                return ICE_GTP;
        case TNL_GTPC:
                return ICE_GTP_NO_PAY;
+       case TNL_PFCP:
+               return ICE_PFCP;
        default:
                return 0;
        }
                return ICE_SW_TUN_GTPU;
        case TNL_GTPC:
                return ICE_SW_TUN_GTPC;
+       case TNL_PFCP:
+               return ICE_SW_TUN_PFCP;
        default:
                return ICE_NON_TUN;
        }
                i++;
        }
 
+       if (flags & ICE_TC_FLWR_FIELD_PFCP_OPTS) {
+               struct ice_pfcp_hdr *hdr_h, *hdr_m;
+
+               hdr_h = &list[i].h_u.pfcp_hdr;
+               hdr_m = &list[i].m_u.pfcp_hdr;
+               list[i].type = ICE_PFCP;
+
+               hdr_h->flags = fltr->pfcp_meta_keys.type;
+               hdr_m->flags = fltr->pfcp_meta_masks.type & 0x01;
+
+               hdr_h->seid = fltr->pfcp_meta_keys.seid;
+               hdr_m->seid = fltr->pfcp_meta_masks.seid;
+
+               i++;
+       }
+
        if (flags & (ICE_TC_FLWR_FIELD_ENC_SRC_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_DEST_IPV4)) {
                list[i].type = ice_proto_type_from_ipv4(false);
        if (tc_fltr->tunnel_type != TNL_LAST) {
                i = ice_tc_fill_tunnel_outer(flags, tc_fltr, list, i);
 
-               headers = &tc_fltr->inner_headers;
-               inner = true;
+               /* PFCP is considered non-tunneled - don't swap headers. */
+               if (tc_fltr->tunnel_type != TNL_PFCP) {
+                       headers = &tc_fltr->inner_headers;
+                       inner = true;
+               }
        }
 
        if (flags & ICE_TC_FLWR_FIELD_ETH_TYPE_ID) {
         */
        if (netif_is_gtp(tunnel_dev))
                return TNL_GTPU;
+       if (netif_is_pfcp(tunnel_dev))
+               return TNL_PFCP;
        return TNL_LAST;
 }
 
                fltr->flags |= ICE_TC_FLWR_FIELD_GTP_OPTS;
        }
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS) &&
+           fltr->tunnel_type == TNL_PFCP) {
+               struct flow_match_enc_opts match;
+
+               flow_rule_match_enc_opts(rule, &match);
+
+               memcpy(&fltr->pfcp_meta_keys, match.key->data,
+                      sizeof(struct pfcp_metadata));
+               memcpy(&fltr->pfcp_meta_masks, match.mask->data,
+                      sizeof(struct pfcp_metadata));
+
+               fltr->flags |= ICE_TC_FLWR_FIELD_PFCP_OPTS;
+       }
+
        return 0;
 }
 
                        return err;
                }
 
-               /* header pointers should point to the inner headers, outer
-                * header were already set by ice_parse_tunnel_attr
-                */
-               headers = &fltr->inner_headers;
+               /* PFCP is considered non-tunneled - don't swap headers. */
+               if (fltr->tunnel_type != TNL_PFCP) {
+                       /* Header pointers should point to the inner headers,
+                        * outer header were already set by
+                        * ice_parse_tunnel_attr().
+                        */
+                       headers = &fltr->inner_headers;
+               }
        } else if (dissector->used_keys &
                  (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
                   BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |