From 93cf3297818ee61607f0a8d1d34e4fb7fcde3cdf Mon Sep 17 00:00:00 2001 From: Luo Jie 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 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 --- .../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,