162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include "lan966x_main.h" 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#define DWRR_COST_BIT_WIDTH BIT(5) 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistatic u32 lan966x_ets_hw_cost(u32 w_min, u32 weight) 862306a36Sopenharmony_ci{ 962306a36Sopenharmony_ci u32 res; 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci /* Round half up: Multiply with 16 before division, 1262306a36Sopenharmony_ci * add 8 and divide result with 16 again 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci res = (((DWRR_COST_BIT_WIDTH << 4) * w_min / weight) + 8) >> 4; 1562306a36Sopenharmony_ci return max_t(u32, 1, res) - 1; 1662306a36Sopenharmony_ci} 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciint lan966x_ets_add(struct lan966x_port *port, 1962306a36Sopenharmony_ci struct tc_ets_qopt_offload *qopt) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct tc_ets_qopt_offload_replace_params *params; 2262306a36Sopenharmony_ci struct lan966x *lan966x = port->lan966x; 2362306a36Sopenharmony_ci u32 w_min = 100; 2462306a36Sopenharmony_ci u8 count = 0; 2562306a36Sopenharmony_ci u32 se_idx; 2662306a36Sopenharmony_ci u8 i; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* Check the input */ 2962306a36Sopenharmony_ci if (qopt->parent != TC_H_ROOT) 3062306a36Sopenharmony_ci return -EINVAL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci params = &qopt->replace_params; 3362306a36Sopenharmony_ci if (params->bands != NUM_PRIO_QUEUES) 3462306a36Sopenharmony_ci return -EINVAL; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci for (i = 0; i < params->bands; ++i) { 3762306a36Sopenharmony_ci /* In the switch the DWRR is always on the lowest consecutive 3862306a36Sopenharmony_ci * priorities. Due to this, the first priority must map to the 3962306a36Sopenharmony_ci * first DWRR band. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci if (params->priomap[i] != (7 - i)) 4262306a36Sopenharmony_ci return -EINVAL; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (params->quanta[i] && params->weights[i] == 0) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci se_idx = SE_IDX_PORT + port->chip_port; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Find minimum weight */ 5162306a36Sopenharmony_ci for (i = 0; i < params->bands; ++i) { 5262306a36Sopenharmony_ci if (params->quanta[i] == 0) 5362306a36Sopenharmony_ci continue; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci w_min = min(w_min, params->weights[i]); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci for (i = 0; i < params->bands; ++i) { 5962306a36Sopenharmony_ci if (params->quanta[i] == 0) 6062306a36Sopenharmony_ci continue; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ++count; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci lan_wr(lan966x_ets_hw_cost(w_min, params->weights[i]), 6562306a36Sopenharmony_ci lan966x, QSYS_SE_DWRR_CFG(se_idx, 7 - i)); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci lan_rmw(QSYS_SE_CFG_SE_DWRR_CNT_SET(count) | 6962306a36Sopenharmony_ci QSYS_SE_CFG_SE_RR_ENA_SET(0), 7062306a36Sopenharmony_ci QSYS_SE_CFG_SE_DWRR_CNT | 7162306a36Sopenharmony_ci QSYS_SE_CFG_SE_RR_ENA, 7262306a36Sopenharmony_ci lan966x, QSYS_SE_CFG(se_idx)); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciint lan966x_ets_del(struct lan966x_port *port, 7862306a36Sopenharmony_ci struct tc_ets_qopt_offload *qopt) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct lan966x *lan966x = port->lan966x; 8162306a36Sopenharmony_ci u32 se_idx; 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci se_idx = SE_IDX_PORT + port->chip_port; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (i = 0; i < NUM_PRIO_QUEUES; ++i) 8762306a36Sopenharmony_ci lan_wr(0, lan966x, QSYS_SE_DWRR_CFG(se_idx, i)); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci lan_rmw(QSYS_SE_CFG_SE_DWRR_CNT_SET(0) | 9062306a36Sopenharmony_ci QSYS_SE_CFG_SE_RR_ENA_SET(0), 9162306a36Sopenharmony_ci QSYS_SE_CFG_SE_DWRR_CNT | 9262306a36Sopenharmony_ci QSYS_SE_CFG_SE_RR_ENA, 9362306a36Sopenharmony_ci lan966x, QSYS_SE_CFG(se_idx)); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 97