From: Til Kaiser <mail@tk154.de>
To: netdev@vger.kernel.org
Cc: Luo Jie <jie.luo@oss.qualcomm.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Simon Horman <horms@kernel.org>, Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
Lei Wei <quic_leiwei@quicinc.com>,
Suruchi Agarwal <quic_suruchia@quicinc.com>,
Pavithra R <quic_pavir@quicinc.com>,
linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
Til Kaiser <mail@tk154.de>
Subject: [PATCH net-next 1/4] net: ethernet: qualcomm: ppe: Select hardware configuration by SoC
Date: Mon, 5 Oct 2026 17:29:12 +0200 [thread overview]
Message-ID: <20261005152915.101780-2-mail@tk154.de> (raw)
In-Reply-To: <20261005152915.101780-1-mail@tk154.de>
The PPE driver hardcodes IPQ9574 parameters: the PPE clock rate,
interconnect paths, port count, buffer limits and scheduler arbitration
tables. Other SoCs with the same PPE architecture need different values.
Move these into per-SoC platform match data, and collect the buffer
manager (BM), queue manager (QM) and scheduler tables in a new struct
ppe_soc_config that is passed to the hardware initialization code. The
IPQ9574 values are unchanged; no functional change intended.
The IPQ9574 scheduler resource table has nine entries, with the reserved
pool at index 8. Select that final entry for port ID num_ports, preserving
the IPQ9574 lookup while allowing a smaller port count on other SoCs.
Rename regmap_config_ipq9574 to ppe_reg_config for the shared PPE
register layout.
Signed-off-by: Til Kaiser <mail@tk154.de>
---
drivers/net/ethernet/qualcomm/ppe/ppe.c | 48 ++++++++++-----
.../net/ethernet/qualcomm/ppe/ppe_config.c | 58 +++++++++++++------
.../net/ethernet/qualcomm/ppe/ppe_config.h | 34 ++++++++++-
3 files changed, 106 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe.c b/drivers/net/ethernet/qualcomm/ppe/ppe.c
index 3c301e609d3e..0ef72c20364b 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -18,13 +19,15 @@
#include "ppe_config.h"
#include "ppe_debugfs.h"
-#define PPE_PORT_MAX 8
-#define PPE_CLK_RATE 353000000
+struct ppe_plat_data {
+ const struct ppe_soc_config *soc_cfg;
+ const struct icc_bulk_data *icc_data;
+ unsigned long ppe_clk_rate;
+ unsigned int num_icc, num_ports;
+};
-/* ICC clocks for enabling PPE device. The avg_bw and peak_bw with value 0
- * will be updated by the clock rate of PPE.
- */
-static const struct icc_bulk_data ppe_icc_data[] = {
+/* IPQ9574 interconnect paths. Zero bandwidths use the PPE clock rate. */
+static const struct icc_bulk_data ipq9574_icc_data[] = {
{
.name = "ppe",
.avg_bw = 0,
@@ -62,6 +65,15 @@ static const struct icc_bulk_data ppe_icc_data[] = {
},
};
+static const struct ppe_plat_data ipq9574_ppe_data = {
+ .soc_cfg = &ipq9574_soc_config,
+ .icc_data = ipq9574_icc_data,
+ .ppe_clk_rate = 353000000,
+ .num_icc = ARRAY_SIZE(ipq9574_icc_data),
+ .num_ports = 8,
+};
+
+/* PPE register access ranges. */
static const struct regmap_range ppe_readable_ranges[] = {
regmap_reg_range(0x0, 0x1ff), /* Global */
regmap_reg_range(0x400, 0x5ff), /* LPI CSR */
@@ -99,7 +111,7 @@ static const struct regmap_access_table ppe_reg_table = {
.n_yes_ranges = ARRAY_SIZE(ppe_readable_ranges),
};
-static const struct regmap_config regmap_config_ipq9574 = {
+static const struct regmap_config ppe_reg_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -108,7 +120,8 @@ static const struct regmap_config regmap_config_ipq9574 = {
.max_register = 0xbef800,
};
-static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev)
+static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev,
+ const struct icc_bulk_data *ppe_icc_data)
{
unsigned long ppe_rate = ppe_dev->clk_rate;
struct device *dev = ppe_dev->dev;
@@ -172,12 +185,17 @@ static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev)
static int qcom_ppe_probe(struct platform_device *pdev)
{
+ const struct ppe_plat_data *plat_data;
struct device *dev = &pdev->dev;
struct ppe_device *ppe_dev;
void __iomem *base;
int ret, num_icc;
- num_icc = ARRAY_SIZE(ppe_icc_data);
+ plat_data = device_get_match_data(dev);
+ if (!plat_data)
+ return -EINVAL;
+
+ num_icc = plat_data->num_icc;
ppe_dev = devm_kzalloc(dev, struct_size(ppe_dev, icc_paths, num_icc),
GFP_KERNEL);
if (!ppe_dev)
@@ -187,20 +205,20 @@ static int qcom_ppe_probe(struct platform_device *pdev)
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base), "PPE ioremap failed\n");
- ppe_dev->regmap = devm_regmap_init_mmio(dev, base, ®map_config_ipq9574);
+ ppe_dev->regmap = devm_regmap_init_mmio(dev, base, &ppe_reg_config);
if (IS_ERR(ppe_dev->regmap))
return dev_err_probe(dev, PTR_ERR(ppe_dev->regmap),
"PPE initialize regmap failed\n");
ppe_dev->dev = dev;
- ppe_dev->clk_rate = PPE_CLK_RATE;
- ppe_dev->num_ports = PPE_PORT_MAX;
+ ppe_dev->clk_rate = plat_data->ppe_clk_rate;
+ ppe_dev->num_ports = plat_data->num_ports;
ppe_dev->num_icc_paths = num_icc;
- ret = ppe_clock_init_and_reset(ppe_dev);
+ ret = ppe_clock_init_and_reset(ppe_dev, plat_data->icc_data);
if (ret)
return dev_err_probe(dev, ret, "PPE clock config failed\n");
- ret = ppe_hw_config(ppe_dev);
+ ret = ppe_hw_config(ppe_dev, plat_data->soc_cfg);
if (ret)
return dev_err_probe(dev, ret, "PPE HW config failed\n");
@@ -219,7 +237,7 @@ static void qcom_ppe_remove(struct platform_device *pdev)
}
static const struct of_device_id qcom_ppe_of_match[] = {
- { .compatible = "qcom,ipq9574-ppe" },
+ { .compatible = "qcom,ipq9574-ppe", .data = &ipq9574_ppe_data },
{}
};
MODULE_DEVICE_TABLE(of, qcom_ppe_of_match);
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_config.c b/drivers/net/ethernet/qualcomm/ppe/ppe_config.c
index 125b73be92b1..65ac6c0841d5 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.c
@@ -835,6 +835,19 @@ static const struct ppe_port_schedule_resource ppe_scheduler_res[] = {
},
};
+const struct ppe_soc_config ipq9574_soc_config = {
+ .bm_group_config = ipq9574_ppe_bm_group_config,
+ .bm_port_config = ipq9574_ppe_bm_port_config,
+ .bm_port_config_cnt = ARRAY_SIZE(ipq9574_ppe_bm_port_config),
+ .qm_group_config = ipq9574_ppe_qm_group_config,
+ .qm_queue_config = ipq9574_ppe_qm_queue_config,
+ .qm_queue_config_cnt = ARRAY_SIZE(ipq9574_ppe_qm_queue_config),
+ .sch_bm_config = ipq9574_ppe_sch_bm_config,
+ .sch_bm_config_cnt = ARRAY_SIZE(ipq9574_ppe_sch_bm_config),
+ .sch_qm_config = ipq9574_ppe_sch_qm_config,
+ .sch_qm_config_cnt = ARRAY_SIZE(ipq9574_ppe_sch_qm_config),
+};
+
/* Set the PPE queue level scheduler configuration. */
static int ppe_scheduler_l0_queue_map_set(struct ppe_device *ppe_dev,
int node_id, int port,
@@ -1080,7 +1093,12 @@ int ppe_port_resource_get(struct ppe_device *ppe_dev, int port,
if (port > ppe_dev->num_ports)
return -EINVAL;
- res = ppe_scheduler_res[port];
+ /* Port ID num_ports selects the reserved pool in the final entry. */
+ if (port == ppe_dev->num_ports)
+ res = ppe_scheduler_res[ARRAY_SIZE(ppe_scheduler_res) - 1];
+ else
+ res = ppe_scheduler_res[port];
+
switch (type) {
case PPE_RES_UCAST:
*res_start = res.ucastq_start;
@@ -1427,7 +1445,8 @@ static int ppe_config_bm_threshold(struct ppe_device *ppe_dev, int bm_port_id,
}
/* Configure the buffer threshold for the port flow control function. */
-static int ppe_config_bm(struct ppe_device *ppe_dev)
+static int ppe_config_bm(struct ppe_device *ppe_dev,
+ const struct ppe_soc_config *soc_cfg)
{
const struct ppe_bm_port_config *port_cfg;
unsigned int i, bm_port_id, port_cfg_cnt;
@@ -1440,7 +1459,7 @@ static int ppe_config_bm(struct ppe_device *ppe_dev)
*/
reg = PPE_BM_SHARED_GROUP_CFG_ADDR;
val = FIELD_PREP(PPE_BM_SHARED_GROUP_CFG_SHARED_LIMIT,
- ipq9574_ppe_bm_group_config);
+ soc_cfg->bm_group_config);
ret = regmap_update_bits(ppe_dev->regmap, reg,
PPE_BM_SHARED_GROUP_CFG_SHARED_LIMIT,
val);
@@ -1448,8 +1467,8 @@ static int ppe_config_bm(struct ppe_device *ppe_dev)
goto bm_config_fail;
/* Configure buffer thresholds for the BM ports. */
- port_cfg = ipq9574_ppe_bm_port_config;
- port_cfg_cnt = ARRAY_SIZE(ipq9574_ppe_bm_port_config);
+ port_cfg = soc_cfg->bm_port_config;
+ port_cfg_cnt = soc_cfg->bm_port_config_cnt;
for (i = 0; i < port_cfg_cnt; i++) {
for (bm_port_id = port_cfg[i].port_id_start;
bm_port_id <= port_cfg[i].port_id_end; bm_port_id++) {
@@ -1470,7 +1489,8 @@ static int ppe_config_bm(struct ppe_device *ppe_dev)
/* Configure PPE hardware queue depth, which is decided by the threshold
* of queue.
*/
-static int ppe_config_qm(struct ppe_device *ppe_dev)
+static int ppe_config_qm(struct ppe_device *ppe_dev,
+ const struct ppe_soc_config *soc_cfg)
{
const struct ppe_qm_queue_config *queue_cfg;
int ret, i, queue_id, queue_cfg_count;
@@ -1485,15 +1505,15 @@ static int ppe_config_qm(struct ppe_device *ppe_dev)
if (ret)
goto qm_config_fail;
- PPE_AC_GRP_SET_BUF_LIMIT(group_cfg, ipq9574_ppe_qm_group_config);
+ PPE_AC_GRP_SET_BUF_LIMIT(group_cfg, soc_cfg->qm_group_config);
ret = regmap_bulk_write(ppe_dev->regmap, reg,
group_cfg, ARRAY_SIZE(group_cfg));
if (ret)
goto qm_config_fail;
- queue_cfg = ipq9574_ppe_qm_queue_config;
- queue_cfg_count = ARRAY_SIZE(ipq9574_ppe_qm_queue_config);
+ queue_cfg = soc_cfg->qm_queue_config;
+ queue_cfg_count = soc_cfg->qm_queue_config_cnt;
for (i = 0; i < queue_cfg_count; i++) {
queue_id = queue_cfg[i].queue_start;
@@ -1625,7 +1645,8 @@ static int ppe_node_scheduler_config(struct ppe_device *ppe_dev,
/* Initialize scheduler settings for PPE buffer utilization and dispatching
* packet on PPE queue.
*/
-static int ppe_config_scheduler(struct ppe_device *ppe_dev)
+static int ppe_config_scheduler(struct ppe_device *ppe_dev,
+ const struct ppe_soc_config *soc_cfg)
{
const struct ppe_scheduler_port_config *port_cfg;
const struct ppe_scheduler_qm_config *qm_cfg;
@@ -1633,8 +1654,8 @@ static int ppe_config_scheduler(struct ppe_device *ppe_dev)
int ret, i, count;
u32 val, reg;
- count = ARRAY_SIZE(ipq9574_ppe_sch_bm_config);
- bm_cfg = ipq9574_ppe_sch_bm_config;
+ count = soc_cfg->sch_bm_config_cnt;
+ bm_cfg = soc_cfg->sch_bm_config;
/* Configure the depth of BM scheduler entries. */
val = FIELD_PREP(PPE_BM_SCH_CTRL_SCH_DEPTH, count);
@@ -1664,8 +1685,8 @@ static int ppe_config_scheduler(struct ppe_device *ppe_dev)
goto sch_config_fail;
}
- count = ARRAY_SIZE(ipq9574_ppe_sch_qm_config);
- qm_cfg = ipq9574_ppe_sch_qm_config;
+ count = soc_cfg->sch_qm_config_cnt;
+ qm_cfg = soc_cfg->sch_qm_config;
/* Configure the depth of QM scheduler entries. */
val = FIELD_PREP(PPE_PSCH_SCH_DEPTH_CFG_SCH_DEPTH, count);
@@ -1995,19 +2016,20 @@ static int ppe_bridge_init(struct ppe_device *ppe_dev)
return 0;
}
-int ppe_hw_config(struct ppe_device *ppe_dev)
+int ppe_hw_config(struct ppe_device *ppe_dev,
+ const struct ppe_soc_config *soc_cfg)
{
int ret;
- ret = ppe_config_bm(ppe_dev);
+ ret = ppe_config_bm(ppe_dev, soc_cfg);
if (ret)
return ret;
- ret = ppe_config_qm(ppe_dev);
+ ret = ppe_config_qm(ppe_dev, soc_cfg);
if (ret)
return ret;
- ret = ppe_config_scheduler(ppe_dev);
+ ret = ppe_config_scheduler(ppe_dev, soc_cfg);
if (ret)
return ret;
diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_config.h b/drivers/net/ethernet/qualcomm/ppe/ppe_config.h
index 60493e51e0a4..0dafab264743 100644
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.h
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.h
@@ -287,7 +287,39 @@ struct ppe_rss_hash_cfg {
u8 hash_fin_outer[PPE_RSS_HASH_TUPLES];
};
-int ppe_hw_config(struct ppe_device *ppe_dev);
+/**
+ * struct ppe_soc_config - SoC-specific PPE hardware configuration.
+ * @bm_group_config: Buffer Management (BM) group configuration.
+ * @bm_port_config: Pointer to the BM port configuration array.
+ * @bm_port_config_cnt: Number of entries in the BM port configuration array.
+ * @qm_group_config: Queue Management (QM) group configuration.
+ * @qm_queue_config: Pointer to the QM queue configuration array.
+ * @qm_queue_config_cnt: Number of entries in the QM queue configuration array.
+ * @sch_bm_config: Pointer to the BM scheduler arbitration array.
+ * @sch_bm_config_cnt: Number of entries in the BM scheduler arbitration array.
+ * @sch_qm_config: Pointer to the QM scheduler arbitration array.
+ * @sch_qm_config_cnt: Number of entries in the QM scheduler arbitration array.
+ */
+struct ppe_soc_config {
+ int bm_group_config;
+ const struct ppe_bm_port_config *bm_port_config;
+ unsigned int bm_port_config_cnt;
+
+ int qm_group_config;
+ const struct ppe_qm_queue_config *qm_queue_config;
+ unsigned int qm_queue_config_cnt;
+
+ const struct ppe_scheduler_bm_config *sch_bm_config;
+ unsigned int sch_bm_config_cnt;
+
+ const struct ppe_scheduler_qm_config *sch_qm_config;
+ unsigned int sch_qm_config_cnt;
+};
+
+extern const struct ppe_soc_config ipq9574_soc_config;
+
+int ppe_hw_config(struct ppe_device *ppe_dev,
+ const struct ppe_soc_config *soc_cfg);
int ppe_queue_scheduler_set(struct ppe_device *ppe_dev,
int node_id, bool flow_level, int port,
struct ppe_scheduler_cfg scheduler_cfg);
--
2.56.0
next prev parent reply other threads:[~2026-10-05 15:36 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-05 15:29 [PATCH net-next 0/4] net: ethernet: qualcomm: ppe: Add IPQ5332 support Til Kaiser
2026-10-05 15:29 ` Til Kaiser [this message]
2026-10-05 15:29 ` [PATCH net-next 2/4] dt-bindings: net: qcom,ipq9574-ppe: Tighten ethernet port node constraints Til Kaiser
2026-10-05 15:29 ` [PATCH net-next 3/4] dt-bindings: net: qcom,ipq9574-ppe: Add IPQ5332 support Til Kaiser
2026-10-05 15:29 ` [PATCH net-next 4/4] net: ethernet: qualcomm: ppe: " Til Kaiser
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261005152915.101780-2-mail@tk154.de \
--to=mail@tk154.de \
--cc=andrew+netdev@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jie.luo@oss.qualcomm.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=quic_leiwei@quicinc.com \
--cc=quic_pavir@quicinc.com \
--cc=quic_suruchia@quicinc.com \
--cc=rdunlap@infradead.org \
--cc=robh@kernel.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®