forked from Openwrt-EcoNet/openwrt
Add the second part of the PPE driver. This includes the EDMA and network device support. This part does not appear to have been officially submitted for upstream review. The series is taken from target/linux/qualcommbe/patches-6.6, and had to be heavily modified in order to compile of v6.12. Changes to patches are noted in the respective patch body. Also add the PPE and EDMA nodes in this series. Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Link: https://github.com/openwrt/openwrt/pull/18796 Signed-off-by: Robert Marko <robimarko@gmail.com>
202 lines
7.1 KiB
Diff
202 lines
7.1 KiB
Diff
From 93cf3297818ee61607f0a8d1d34e4fb7fcde3cdf Mon Sep 17 00:00:00 2001
|
|
From: Luo Jie <quic_luoj@quicinc.com>
|
|
Date: Tue, 26 Dec 2023 20:18:09 +0800
|
|
Subject: [PATCH] net: ethernet: qualcomm: Add PPE scheduler config
|
|
|
|
PPE scheduler config determines the priority of scheduling the
|
|
packet. The scheduler config is used for supporting the QoS
|
|
offload in PPE hardware.
|
|
|
|
Change-Id: I4811bd133074757371775a6a69a1cc3cfaa8d0d0
|
|
Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
|
|
Alex G: rebase patch on top of PPE driver submission from 20250209.
|
|
Add the ppe_queue_priority_set() function and its
|
|
dependencies. They will be used in the edma support in
|
|
susequent changes.
|
|
ppe_queue_priority_set() used to be part of ppe_api.c, and
|
|
is hereby moved to ppe_config.c .
|
|
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
|
---
|
|
.../net/ethernet/qualcomm/ppe/ppe_config.c | 141 ++++++++++++++++++
|
|
.../net/ethernet/qualcomm/ppe/ppe_config.h | 5 +
|
|
2 files changed, 146 insertions(+)
|
|
|
|
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.c
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.c
|
|
@@ -864,6 +864,51 @@ static int ppe_scheduler_l0_queue_map_se
|
|
val);
|
|
}
|
|
|
|
+/* Get the first level scheduler configuration. */
|
|
+static int ppe_scheduler_l0_queue_map_get(struct ppe_device *ppe_dev,
|
|
+ int node_id, int *port,
|
|
+ struct ppe_scheduler_cfg *scheduler_cfg)
|
|
+{
|
|
+ u32 val, reg;
|
|
+ int ret;
|
|
+
|
|
+ reg = PPE_L0_FLOW_MAP_TBL_ADDR + node_id * PPE_L0_FLOW_MAP_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->flow_id = FIELD_GET(PPE_L0_FLOW_MAP_TBL_FLOW_ID, val);
|
|
+ scheduler_cfg->pri = FIELD_GET(PPE_L0_FLOW_MAP_TBL_C_PRI, val);
|
|
+ scheduler_cfg->drr_node_wt = FIELD_GET(PPE_L0_FLOW_MAP_TBL_C_NODE_WT, val);
|
|
+
|
|
+ reg = PPE_L0_C_FLOW_CFG_TBL_ADDR +
|
|
+ (scheduler_cfg->flow_id * PPE_QUEUE_SCH_PRI_NUM + scheduler_cfg->pri) *
|
|
+ PPE_L0_C_FLOW_CFG_TBL_INC;
|
|
+
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->drr_node_id = FIELD_GET(PPE_L0_C_FLOW_CFG_TBL_NODE_ID, val);
|
|
+ scheduler_cfg->unit_is_packet = FIELD_GET(PPE_L0_C_FLOW_CFG_TBL_NODE_CREDIT_UNIT, val);
|
|
+
|
|
+ reg = PPE_L0_FLOW_PORT_MAP_TBL_ADDR + node_id * PPE_L0_FLOW_PORT_MAP_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ *port = FIELD_GET(PPE_L0_FLOW_PORT_MAP_TBL_PORT_NUM, val);
|
|
+
|
|
+ reg = PPE_L0_COMP_CFG_TBL_ADDR + node_id * PPE_L0_COMP_CFG_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->frame_mode = FIELD_GET(PPE_L0_COMP_CFG_TBL_NODE_METER_LEN, val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Set the PPE flow level scheduler configuration. */
|
|
static int ppe_scheduler_l1_queue_map_set(struct ppe_device *ppe_dev,
|
|
int node_id, int port,
|
|
@@ -916,6 +961,50 @@ static int ppe_scheduler_l1_queue_map_se
|
|
return regmap_update_bits(ppe_dev->regmap, reg, PPE_L1_COMP_CFG_TBL_NODE_METER_LEN, val);
|
|
}
|
|
|
|
+/* Get the second level scheduler configuration. */
|
|
+static int ppe_scheduler_l1_queue_map_get(struct ppe_device *ppe_dev,
|
|
+ int node_id, int *port,
|
|
+ struct ppe_scheduler_cfg *scheduler_cfg)
|
|
+{
|
|
+ u32 val, reg;
|
|
+ int ret;
|
|
+
|
|
+ reg = PPE_L1_FLOW_MAP_TBL_ADDR + node_id * PPE_L1_FLOW_MAP_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->flow_id = FIELD_GET(PPE_L1_FLOW_MAP_TBL_FLOW_ID, val);
|
|
+ scheduler_cfg->pri = FIELD_GET(PPE_L1_FLOW_MAP_TBL_C_PRI, val);
|
|
+ scheduler_cfg->drr_node_wt = FIELD_GET(PPE_L1_FLOW_MAP_TBL_C_NODE_WT, val);
|
|
+
|
|
+ reg = PPE_L1_C_FLOW_CFG_TBL_ADDR +
|
|
+ (scheduler_cfg->flow_id * PPE_QUEUE_SCH_PRI_NUM + scheduler_cfg->pri) *
|
|
+ PPE_L1_C_FLOW_CFG_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->drr_node_id = FIELD_GET(PPE_L1_C_FLOW_CFG_TBL_NODE_ID, val);
|
|
+ scheduler_cfg->unit_is_packet = FIELD_GET(PPE_L1_C_FLOW_CFG_TBL_NODE_CREDIT_UNIT, val);
|
|
+
|
|
+ reg = PPE_L1_FLOW_PORT_MAP_TBL_ADDR + node_id * PPE_L1_FLOW_PORT_MAP_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ *port = FIELD_GET(PPE_L1_FLOW_PORT_MAP_TBL_PORT_NUM, val);
|
|
+
|
|
+ reg = PPE_L1_COMP_CFG_TBL_ADDR + node_id * PPE_L1_COMP_CFG_TBL_INC;
|
|
+ ret = regmap_read(ppe_dev->regmap, reg, &val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ scheduler_cfg->frame_mode = FIELD_GET(PPE_L1_COMP_CFG_TBL_NODE_METER_LEN, val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* ppe_queue_scheduler_set - Configure scheduler for PPE hardware queue
|
|
* @ppe_dev: PPE device
|
|
@@ -942,6 +1031,58 @@ int ppe_queue_scheduler_set(struct ppe_d
|
|
}
|
|
|
|
/**
|
|
+ * ppe_queue_scheduler_get - get QoS scheduler of PPE hardware queue
|
|
+ * @ppe_dev: PPE device
|
|
+ * @node_id: PPE node ID
|
|
+ * @flow_level: Flow level scheduler or queue level scheduler
|
|
+ * @port: PPE port ID to get scheduler config
|
|
+ * @scheduler_cfg: QoS scheduler configuration
|
|
+ *
|
|
+ * The hardware QoS function is supported by PPE, the current scheduler
|
|
+ * configuration can be acquired based on the queue ID of PPE port.
|
|
+ *
|
|
+ * Return 0 on success, negative error code on failure.
|
|
+ */
|
|
+int ppe_queue_scheduler_get(struct ppe_device *ppe_dev,
|
|
+ int node_id, bool flow_level, int *port,
|
|
+ struct ppe_scheduler_cfg *scheduler_cfg)
|
|
+{
|
|
+ if (flow_level)
|
|
+ return ppe_scheduler_l1_queue_map_get(ppe_dev, node_id,
|
|
+ port, scheduler_cfg);
|
|
+
|
|
+ return ppe_scheduler_l0_queue_map_get(ppe_dev, node_id,
|
|
+ port, scheduler_cfg);
|
|
+}
|
|
+
|
|
+
|
|
+/**
|
|
+ * ppe_queue_priority_set - set scheduler priority of PPE hardware queue
|
|
+ * @ppe_dev: PPE device
|
|
+ * @node_id: PPE hardware node ID, which is either queue ID or flow ID
|
|
+ * @priority: Qos scheduler priority
|
|
+ *
|
|
+ * Configure scheduler priority of PPE hardware queque, the maximum node
|
|
+ * ID supported is PPE_QUEUE_ID_NUM added by PPE_FLOW_ID_NUM, queue ID
|
|
+ * belongs to level 0, flow ID belongs to level 1 in the packet pipeline.
|
|
+ *
|
|
+ * Return 0 on success, negative error code on failure.
|
|
+ */
|
|
+int ppe_queue_priority_set(struct ppe_device *ppe_dev,
|
|
+ int node_id, int priority)
|
|
+{
|
|
+ struct ppe_scheduler_cfg sch_cfg;
|
|
+ int ret, port, level = 0;
|
|
+
|
|
+ ret = ppe_queue_scheduler_get(ppe_dev, node_id, level, &port, &sch_cfg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ sch_cfg.pri = priority;
|
|
+ return ppe_queue_scheduler_set(ppe_dev, node_id, level, port, sch_cfg);
|
|
+}
|
|
+
|
|
+/**
|
|
* ppe_queue_ucast_base_set - Set PPE unicast queue base ID and profile ID
|
|
* @ppe_dev: PPE device
|
|
* @queue_dst: PPE queue destination configuration
|
|
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_config.h
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_config.h
|
|
@@ -291,6 +291,11 @@ int ppe_hw_config(struct ppe_device *ppe
|
|
int ppe_queue_scheduler_set(struct ppe_device *ppe_dev,
|
|
int node_id, bool flow_level, int port,
|
|
struct ppe_scheduler_cfg scheduler_cfg);
|
|
+int ppe_queue_scheduler_get(struct ppe_device *ppe_dev,
|
|
+ int node_id, bool flow_level, int *port,
|
|
+ struct ppe_scheduler_cfg *scheduler_cfg);
|
|
+int ppe_queue_priority_set(struct ppe_device *ppe_dev,
|
|
+ int queue_id, int priority);
|
|
int ppe_queue_ucast_base_set(struct ppe_device *ppe_dev,
|
|
struct ppe_queue_ucast_dest queue_dst,
|
|
int queue_base,
|