diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.c b/drivers/net/ethernet/qualcomm/ppe/ppe.c
index 23f9de105062..94fa13dd17da 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/soc/qcom/ppe.h>
 #include "ppe.h"
+#include "ppe_regs.h"
 
 static const char * const ppe_clock_name[PPE_CLK_MAX] = {
 	"cmn_ahb",
@@ -111,6 +112,49 @@ static const char * const ppe_reset_name[PPE_RST_MAX] = {
 	"nss_port6_mac",
 };
 
+int ppe_write(struct ppe_device *ppe_dev, u32 reg, unsigned int val)
+{
+	return regmap_write(ppe_dev->regmap, reg, val);
+}
+
+int ppe_read(struct ppe_device *ppe_dev, u32 reg, unsigned int *val)
+{
+	return regmap_read(ppe_dev->regmap, reg, val);
+}
+
+int ppe_mask(struct ppe_device *ppe_dev, u32 reg, u32 mask, unsigned int set)
+{
+	return regmap_update_bits(ppe_dev->regmap, reg, mask, set);
+}
+
+int ppe_write_tbl(struct ppe_device *ppe_dev, u32 reg,
+		  const unsigned int *val, int cnt)
+{
+	int i, ret;
+
+	for (i = 0; i < cnt / 4; i++) {
+		ret = ppe_write(ppe_dev, reg + i * 4, val[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int ppe_read_tbl(struct ppe_device *ppe_dev, u32 reg,
+		 unsigned int *val, int cnt)
+{
+	int i, ret;
+
+	for (i = 0; i < cnt / 4; i++) {
+		ret = ppe_read(ppe_dev, reg + i * 4, &val[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
 int ppe_type_get(struct ppe_device *ppe_dev)
 {
 	struct ppe_data *ppe_dev_priv = ppe_dev->ppe_priv;
@@ -323,6 +367,120 @@ static struct ppe_data *ppe_data_init(struct platform_device *pdev)
 	return ppe_dev_priv;
 }
 
+static int of_parse_ppe_bm(struct ppe_device *ppe_dev,
+			   struct device_node *ppe_node)
+{
+	union ppe_bm_port_fc_cfg_u fc_cfg;
+	struct device_node *bm_node;
+	int ret, cnt;
+	u32 *cfg, reg_val;
+
+	bm_node = of_get_child_by_name(ppe_node, "buffer-management-config");
+	if (!bm_node)
+		return dev_err_probe(ppe_dev->dev, -ENODEV,
+				     "Fail to get buffer-management-config\n");
+
+	cnt = of_property_count_u32_elems(bm_node, "qcom,group-config");
+	if (cnt < 0)
+		return dev_err_probe(ppe_dev->dev, cnt,
+				     "Fail to qcom,group-config\n");
+
+	cfg = kmalloc_array(cnt, sizeof(*cfg), GFP_KERNEL | __GFP_ZERO);
+	if (!cfg)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(bm_node, "qcom,group-config", cfg, cnt);
+	if (ret) {
+		dev_err(ppe_dev->dev, "Fail to get qcom,group-config %d\n", ret);
+		goto parse_bm_err;
+	}
+
+	/* Parse BM group configuration,
+	 * the dts propert: qcom,group-config = <group group_buf>;
+	 *
+	 * There are 3 kinds of buffer types, guaranteed buffer(port based),
+	 * shared buffer(group based) and react buffer(cache in-flight packets).
+	 *
+	 * Maximum 4 groups supported by PPE.
+	 */
+	ret = 0;
+	while ((cnt - ret) / 2) {
+		if (cfg[ret] < PPE_BM_SHARED_GROUP_CFG_NUM) {
+			reg_val = FIELD_PREP(PPE_BM_SHARED_GROUP_CFG_SHARED_LIMIT, cfg[ret + 1]);
+
+			ppe_write(ppe_dev, PPE_BM_SHARED_GROUP_CFG +
+				  PPE_BM_SHARED_GROUP_CFG_INC * cfg[ret], reg_val);
+		}
+		ret += 2;
+	}
+
+	cnt = of_property_count_u32_elems(bm_node, "qcom,port-config");
+	if (cnt < 0) {
+		dev_err(ppe_dev->dev, "Fail to get qcom,port-config %d\n", cnt);
+		goto parse_bm_err;
+	}
+
+	cfg = krealloc_array(cfg, cnt, sizeof(*cfg), GFP_KERNEL | __GFP_ZERO);
+	if (!cfg) {
+		ret = -ENOMEM;
+		goto parse_bm_err;
+	}
+
+	ret = of_property_read_u32_array(bm_node, "qcom,port-config", cfg, cnt);
+	if (ret) {
+		dev_err(ppe_dev->dev, "Fail to get qcom,port-config %d\n", ret);
+		goto parse_bm_err;
+	}
+
+	/* Parse BM port configuration,
+	 * the dts property: qcom,port-config = <group port prealloc react ceil
+	 * weight res_off res_ceil dynamic>;
+	 *
+	 * The port based buffer is assigned to the group ID, which is the
+	 * buffer dedicated to BM port, and the threshold to generate the
+	 * pause frame, the threshold can be configured as the static value
+	 * or dynamically adjusted according to the remain buffer.
+	 */
+	ret = 0;
+	while ((cnt - ret) / 9) {
+		if (cfg[ret + 1] < PPE_BM_PORT_FC_MODE_NUM) {
+			memset(&fc_cfg, 0, sizeof(fc_cfg));
+
+			fc_cfg.bf.pre_alloc = cfg[ret + 2];
+			fc_cfg.bf.react_limit = cfg[ret + 3];
+			fc_cfg.bf.shared_ceiling_0 = cfg[ret + 4] & 0x7;
+			fc_cfg.bf.shared_ceiling_1 = cfg[ret + 4] >> 3;
+			fc_cfg.bf.shared_weight = cfg[ret + 5];
+			fc_cfg.bf.resum_offset = cfg[ret + 6];
+			fc_cfg.bf.resum_floor_th = cfg[ret + 7];
+			fc_cfg.bf.shared_dynamic = cfg[ret + 8];
+			ppe_write_tbl(ppe_dev, PPE_BM_PORT_FC_CFG +
+				      PPE_BM_PORT_FC_CFG_INC * cfg[ret + 1],
+				      fc_cfg.val, sizeof(fc_cfg.val));
+
+			reg_val = FIELD_PREP(PPE_BM_PORT_GROUP_ID_SHARED_GROUP_ID, cfg[ret]);
+			ppe_write(ppe_dev, PPE_BM_PORT_GROUP_ID +
+				  PPE_BM_PORT_GROUP_ID_INC * cfg[ret + 1], reg_val);
+
+			reg_val = FIELD_PREP(PPE_BM_PORT_FC_MODE_EN, 1);
+			ppe_write(ppe_dev, PPE_BM_PORT_FC_MODE +
+				  PPE_BM_PORT_FC_MODE_INC * cfg[ret + 1], reg_val);
+		}
+		ret += 9;
+	}
+	ret = 0;
+
+parse_bm_err:
+	kfree(cfg);
+	return ret;
+}
+
+static int of_parse_ppe_config(struct ppe_device *ppe_dev,
+			       struct device_node *ppe_node)
+{
+	return of_parse_ppe_bm(ppe_dev, ppe_node);
+}
+
 static int qcom_ppe_probe(struct platform_device *pdev)
 {
 	struct ppe_device *ppe_dev;
@@ -359,6 +517,12 @@ static int qcom_ppe_probe(struct platform_device *pdev)
 				     ret,
 				     "ppe clock config failed\n");
 
+	ret = of_parse_ppe_config(ppe_dev, pdev->dev.of_node);
+	if (ret)
+		return dev_err_probe(&pdev->dev,
+				     ret,
+				     "of parse ppe failed\n");
+
 	ppe_dev->is_ppe_probed = true;
 	return 0;
 }
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.h b/drivers/net/ethernet/qualcomm/ppe/ppe.h
index f54406a6feb7..6caef42ab235 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe.h
@@ -140,4 +140,10 @@ struct ppe_data {
 };
 
 int ppe_type_get(struct ppe_device *ppe_dev);
+
+int ppe_write(struct ppe_device *ppe_dev, u32 reg, unsigned int val);
+int ppe_read(struct ppe_device *ppe_dev, u32 reg, unsigned int *val);
+int ppe_mask(struct ppe_device *ppe_dev, u32 reg, u32 mask, unsigned int set);
+int ppe_write_tbl(struct ppe_device *ppe_dev, u32 reg, const unsigned int *val, int cnt);
+int ppe_read_tbl(struct ppe_device *ppe_dev, u32 reg, unsigned int *val, int cnt);
 #endif
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
new file mode 100644
index 000000000000..e11d8f2a26b7
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_regs.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+/* PPE hardware register and table declarations. */
+#ifndef __PPE_REGS_H__
+#define __PPE_REGS_H__
+
+#define PPE_BM_PORT_FC_MODE					0x600100
+#define PPE_BM_PORT_FC_MODE_NUM					15
+#define PPE_BM_PORT_FC_MODE_INC					4
+#define PPE_BM_PORT_FC_MODE_EN					BIT(0)
+
+#define PPE_BM_PORT_GROUP_ID					0x600180
+#define PPE_BM_PORT_GROUP_ID_NUM				15
+#define PPE_BM_PORT_GROUP_ID_INC				4
+#define PPE_BM_PORT_GROUP_ID_SHARED_GROUP_ID			GENMASK(1, 0)
+
+#define PPE_BM_SHARED_GROUP_CFG					0x600290
+#define PPE_BM_SHARED_GROUP_CFG_NUM				4
+#define PPE_BM_SHARED_GROUP_CFG_INC				4
+#define PPE_BM_SHARED_GROUP_CFG_SHARED_LIMIT			GENMASK(10, 0)
+
+#define PPE_BM_PORT_FC_CFG					0x601000
+#define PPE_BM_PORT_FC_CFG_NUM					15
+#define PPE_BM_PORT_FC_CFG_INC					0x10
+
+/* BM port configurations, BM port(0-7) for CPU port, BM port(8-13) for physical
+ * port 1-6.
+ */
+struct ppe_bm_port_fc_cfg {
+	u32 react_limit:9,
+	    resum_floor_th:9,
+	    resum_offset:11,
+	    shared_ceiling_0:3;
+	u32 shared_ceiling_1:8,
+	    shared_weight:3,
+	    shared_dynamic:1,
+	    pre_alloc:11,
+	    res0:9;
+};
+
+union ppe_bm_port_fc_cfg_u {
+	u32 val[2];
+	struct ppe_bm_port_fc_cfg bf;
+};
+
+#endif
