diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.c b/drivers/net/ethernet/qualcomm/ppe/ppe.c
index dd032a158231..acff37f9d832 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe.c
@@ -1104,9 +1104,29 @@ static int ppe_qm_init(struct ppe_device *ppe_dev)
 	return 0;
 }
 
+static int ppe_servcode_init(struct ppe_device *ppe_dev)
+{
+	struct ppe_servcode_cfg servcode_cfg;
+
+	memset(&servcode_cfg, 0, sizeof(servcode_cfg));
+	servcode_cfg.bypass_bitmap[0] = (u32)(~(BIT(FAKE_MAC_HEADER_BYP) |
+					BIT(SERVICE_CODE_BYP) |
+					BIT(FAKE_L2_PROTO_BYP)));
+	servcode_cfg.bypass_bitmap[1] = (u32)(~(BIT(ACL_POST_ROUTING_CHECK_BYP)));
+
+	/* The default service code used by CPU port */
+	return ppe_servcode_config_set(ppe_dev, 1, servcode_cfg);
+}
+
 static int ppe_dev_hw_init(struct ppe_device *ppe_dev)
 {
-	return ppe_qm_init(ppe_dev);
+	int ret;
+
+	ret = ppe_qm_init(ppe_dev);
+	if (ret)
+		return ret;
+
+	return ppe_servcode_init(ppe_dev);
 }
 
 static int qcom_ppe_probe(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_ops.c b/drivers/net/ethernet/qualcomm/ppe/ppe_ops.c
index eaa3f1e7b525..a3269c0898be 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_ops.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_ops.c
@@ -269,6 +269,48 @@ static int ppe_queue_ucast_hash_class_set(struct ppe_device *ppe_dev,
 			 reg_val);
 }
 
+int ppe_servcode_config_set(struct ppe_device *ppe_dev,
+			    int servcode,
+			    struct ppe_servcode_cfg cfg)
+{
+	union ppe_eg_service_cfg_u eg_service_cfg;
+	union ppe_service_cfg_u service_cfg;
+	int val;
+
+	memset(&service_cfg, 0, sizeof(service_cfg));
+	memset(&eg_service_cfg, 0, sizeof(eg_service_cfg));
+
+	val = FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_PORT_ID_VALID, cfg.dest_port_valid) |
+		FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_PORT_ID, cfg.dest_port) |
+		FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_DIRECTION, cfg.is_src) |
+		FIELD_PREP(PPE_IN_L2_SERVICE_TBL_DST_BYPASS_BITMAP, cfg.bypass_bitmap[1]) |
+		FIELD_PREP(PPE_IN_L2_SERVICE_TBL_RX_CNT_EN,
+			   cfg.bypass_bitmap[2] & BIT(1) ? 1 : 0) |
+		FIELD_PREP(PPE_IN_L2_SERVICE_TBL_TX_CNT_EN,
+			   cfg.bypass_bitmap[2] & BIT(3) ? 1 : 0);
+	ppe_write(ppe_dev, PPE_IN_L2_SERVICE_TBL + PPE_IN_L2_SERVICE_TBL_INC * servcode, val);
+
+	ppe_read_tbl(ppe_dev, PPE_SERVICE_TBL + PPE_SERVICE_TBL_INC * servcode,
+		     service_cfg.val, sizeof(service_cfg.val));
+	service_cfg.bf.bypass_bitmap = cfg.bypass_bitmap[0];
+	service_cfg.bf.rx_counting_en = cfg.bypass_bitmap[2] & BIT(0);
+	ppe_write_tbl(ppe_dev, PPE_SERVICE_TBL + PPE_SERVICE_TBL_INC * servcode,
+		      service_cfg.val, sizeof(service_cfg.val));
+
+	ppe_read_tbl(ppe_dev, PPE_EG_SERVICE_TBL + PPE_EG_SERVICE_TBL_INC * servcode,
+		     eg_service_cfg.val, sizeof(eg_service_cfg.val));
+	eg_service_cfg.bf.field_update_action = cfg.field_update_bitmap;
+	eg_service_cfg.bf.next_service_code = cfg.next_service_code;
+	eg_service_cfg.bf.hw_services = cfg.hw_service;
+	eg_service_cfg.bf.offset_sel = cfg.offset_sel;
+	eg_service_cfg.bf.tx_counting_en = cfg.bypass_bitmap[2] & BIT(2) ? 1 : 0;
+	ppe_write_tbl(ppe_dev, PPE_EG_SERVICE_TBL + PPE_EG_SERVICE_TBL_INC * servcode,
+		      eg_service_cfg.val, sizeof(eg_service_cfg.val));
+
+	val = FIELD_PREP(PPE_TL_SERVICE_TBL_BYPASS_BITMAP, cfg.bypass_bitmap[3]);
+	return ppe_write(ppe_dev, PPE_TL_SERVICE_TBL + PPE_TL_SERVICE_TBL_INC * servcode, val);
+}
+
 static const struct ppe_queue_ops qcom_ppe_queue_config_ops = {
 	.queue_scheduler_set = ppe_queue_scheduler_set,
 	.queue_scheduler_get = ppe_queue_scheduler_get,
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_ops.h b/drivers/net/ethernet/qualcomm/ppe/ppe_ops.h
index 181dbd4a3d90..b3c1ade7c948 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_ops.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_ops.h
@@ -45,6 +45,109 @@ struct ppe_queue_ucast_dest {
 	int dest_port;
 };
 
+/* bypss_bitmap_0 */
+enum {
+	IN_VLAN_TAG_FMT_CHECK_BYP = 0,
+	IN_VLAN_MEMBER_CHECK_BYP,
+	IN_VLAN_XLT_BYP,
+	MY_MAC_CHECK_BYP,
+	DIP_LOOKUP_BYP,
+	FLOW_LOOKUP_BYP = 5,
+	FLOW_ACTION_BYP,
+	ACL_BYP,
+	FAKE_MAC_HEADER_BYP,
+	SERVICE_CODE_BYP,
+	WRONG_PKT_FMT_L2_BYP = 10,
+	WRONG_PKT_FMT_L3_IPV4_BYP,
+	WRONG_PKT_FMT_L3_IPV6_BYP,
+	WRONG_PKT_FMT_L4_BYP,
+	FLOW_SERVICE_CODE_BYP,
+	ACL_SERVICE_CODE_BYP = 15,
+	FAKE_L2_PROTO_BYP,
+	PPPOE_TERMINATION_BYP,
+	DEFAULT_VLAN_BYP,
+	DEFAULT_PCP_BYP,
+	VSI_ASSIGN_BYP,
+	IN_VLAN_ASSIGN_FAIL_BYP = 24,
+	SOURCE_GUARD_BYP,
+	MRU_MTU_CHECK_BYP,
+	FLOW_SRC_CHECK_BYP,
+	FLOW_QOS_BYP,
+};
+
+/* bypss_bitmap_1 */
+enum {
+	EG_VLAN_MEMBER_CHECK_BYP = 0,
+	EG_VLAN_XLT_BYP,
+	EG_VLAN_TAG_FMT_CTRL_BYP,
+	FDB_LEARN_BYP,
+	FDB_REFRESH_BYP,
+	L2_SOURCE_SEC_BYP = 5,
+	MANAGEMENT_FWD_BYP,
+	BRIDGING_FWD_BYP,
+	IN_STP_FLTR_BYP,
+	EG_STP_FLTR_BYP,
+	SOURCE_FLTR_BYP = 10,
+	POLICER_BYP,
+	L2_PKT_EDIT_BYP,
+	L3_PKT_EDIT_BYP,
+	ACL_POST_ROUTING_CHECK_BYP,
+	PORT_ISOLATION_BYP = 15,
+	PRE_ACL_QOS_BYP,
+	POST_ACL_QOS_BYP,
+	DSCP_QOS_BYP,
+	PCP_QOS_BYP,
+	PREHEADER_QOS_BYP = 20,
+	FAKE_MAC_DROP_BYP,
+	TUNL_CONTEXT_BYP,
+	FLOW_POLICER_BYP,
+};
+
+/* bypss_bitmap_2 */
+enum {
+	RX_VLAN_COUNTER_BYP = 0,
+	RX_COUNTER_BYP,
+	TX_VLAN_COUNTER_BYP,
+	TX_COUNTER_BYP,
+};
+
+/* bypass_bitmap_3 */
+enum {
+	TL_SERVICE_CODE_BYP = 0,
+	TL_BYP,
+	TL_L3_IF_CHECK_BYP,
+	TL_VLAN_CHECK_BYP,
+	TL_DMAC_CHECK_BYP,
+	TL_UDP_CSUM_0_CHECK_BYP = 5,
+	TL_TBL_DE_ACCE_CHECK_BYP,
+	TL_PPPOE_MC_TERM_CHECK_BYP,
+	TL_TTL_EXCEED_CHECK_BYP,
+	TL_MAP_SRC_CHECK_BYP,
+	TL_MAP_DST_CHECK_BYP = 10,
+	TL_LPM_DST_LOOKUP_BYP,
+	TL_LPM_LOOKUP_BYP,
+	TL_WRONG_PKT_FMT_L2_BYP,
+	TL_WRONG_PKT_FMT_L3_IPV4_BYP,
+	TL_WRONG_PKT_FMT_L3_IPV6_BYP = 15,
+	TL_WRONG_PKT_FMT_L4_BYP,
+	TL_WRONG_PKT_FMT_TUNNEL_BYP,
+	TL_PRE_IPO_BYP = 20,
+};
+
+/* PPE service code is used to bypass hardware handler when the packet pass
+ * through PPE, the supported service code number is 256.
+ */
+struct ppe_servcode_cfg {
+	bool dest_port_valid;
+	int dest_port;
+	u32 bypass_bitmap[4];
+	bool is_src;
+	int field_update_bitmap;
+	int next_service_code;
+	int hw_service;
+	int offset_sel;
+};
+
 /* The operations are used to configure the PPE queue related resource */
 struct ppe_queue_ops {
 	int (*queue_scheduler_set)(struct ppe_device *ppe_dev,
@@ -76,4 +179,8 @@ struct ppe_queue_ops {
 };
 
 const struct ppe_queue_ops *ppe_queue_config_ops_get(void);
+
+int ppe_servcode_config_set(struct ppe_device *ppe_dev,
+			    int servcode,
+			    struct ppe_servcode_cfg cfg);
 #endif
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
index 9fdb9592b44b..66ddfd5cd123 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
@@ -23,9 +23,71 @@
 #define PPE_BM_TDM_CFG_TBL_SECOND_PORT_VALID			BIT(6)
 #define PPE_BM_TDM_CFG_TBL_SECOND_PORT				GENMASK(11, 8)
 
+#define PPE_SERVICE_TBL						0x15000
+#define PPE_SERVICE_TBL_NUM					256
+#define PPE_SERVICE_TBL_INC					0x10
+#define PPE_SERVICE_TBL_BYPASS_BITMAP				GENMASK(31, 0)
+#define PPE_SERVICE_TBL_RX_COUNTING_EN				BIT(32)
+
+/* service code for the ingress packet, the PPE features can be bypassed
+ * with service config.
+ */
+struct ppe_service_cfg {
+	u32 bypass_bitmap;
+	u32 rx_counting_en:1,
+	    res0:31;
+};
+
+union ppe_service_cfg_u {
+	u32 val[2];
+	struct ppe_service_cfg bf;
+};
+
 #define PPE_EG_BRIDGE_CONFIG					0x20044
 #define PPE_EG_BRIDGE_CONFIG_QUEUE_CNT_EN			BIT(2)
 
+#define PPE_EG_SERVICE_TBL					0x43000
+#define PPE_EG_SERVICE_TBL_NUM					256
+#define PPE_EG_SERVICE_TBL_INC					0x10
+
+/* service code config for the egress packet, the new service code can be
+ * generated and ath header can be configured.
+ */
+struct ppe_eg_service_cfg {
+	u32 field_update_action;
+	u32 next_service_code:8,
+	    hw_services:6,
+	    offset_sel:1,
+	    tx_counting_en:1,
+	    ip_length_update:1,
+	    ath_hdr_insert_dis:1,
+	    ath_hdr_type:3,
+	    ath_from_cpu:1,
+	    ath_disable_bit:1,
+	    ath_port_bitmap:7,
+	    res0:2;
+};
+
+union ppe_eg_service_cfg_u {
+	u32 val[2];
+	struct ppe_eg_service_cfg bf;
+};
+
+#define PPE_IN_L2_SERVICE_TBL					0x66000
+#define PPE_IN_L2_SERVICE_TBL_NUM				256
+#define PPE_IN_L2_SERVICE_TBL_INC				0x10
+#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID_VALID			BIT(0)
+#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID			GENMASK(4, 1)
+#define PPE_IN_L2_SERVICE_TBL_DST_DIRECTION			BIT(5)
+#define PPE_IN_L2_SERVICE_TBL_DST_BYPASS_BITMAP			GENMASK(29, 6)
+#define PPE_IN_L2_SERVICE_TBL_RX_CNT_EN				BIT(30)
+#define PPE_IN_L2_SERVICE_TBL_TX_CNT_EN				BIT(31)
+
+#define PPE_TL_SERVICE_TBL					0x306000
+#define PPE_TL_SERVICE_TBL_NUM					256
+#define PPE_TL_SERVICE_TBL_INC					4
+#define PPE_TL_SERVICE_TBL_BYPASS_BITMAP			GENMASK(31, 0)
+
 #define PPE_PSCH_TDM_DEPTH_CFG					0x400000
 #define PPE_PSCH_TDM_DEPTH_CFG_NUM				1
 #define PPE_PSCH_TDM_DEPTH_CFG_INC				4
