162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include "lan966x_main.h" 462306a36Sopenharmony_ci 562306a36Sopenharmony_ciint lan966x_tbf_add(struct lan966x_port *port, 662306a36Sopenharmony_ci struct tc_tbf_qopt_offload *qopt) 762306a36Sopenharmony_ci{ 862306a36Sopenharmony_ci struct lan966x *lan966x = port->lan966x; 962306a36Sopenharmony_ci bool root = qopt->parent == TC_H_ROOT; 1062306a36Sopenharmony_ci u32 queue = 0; 1162306a36Sopenharmony_ci u32 cir, cbs; 1262306a36Sopenharmony_ci u32 se_idx; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci if (!root) { 1562306a36Sopenharmony_ci queue = TC_H_MIN(qopt->parent) - 1; 1662306a36Sopenharmony_ci if (queue >= NUM_PRIO_QUEUES) 1762306a36Sopenharmony_ci return -EOPNOTSUPP; 1862306a36Sopenharmony_ci } 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (root) 2162306a36Sopenharmony_ci se_idx = SE_IDX_PORT + port->chip_port; 2262306a36Sopenharmony_ci else 2362306a36Sopenharmony_ci se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci cir = div_u64(qopt->replace_params.rate.rate_bytes_ps, 1000) * 8; 2662306a36Sopenharmony_ci cbs = qopt->replace_params.max_size; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* Rate unit is 100 kbps */ 2962306a36Sopenharmony_ci cir = DIV_ROUND_UP(cir, 100); 3062306a36Sopenharmony_ci /* Avoid using zero rate */ 3162306a36Sopenharmony_ci cir = cir ?: 1; 3262306a36Sopenharmony_ci /* Burst unit is 4kB */ 3362306a36Sopenharmony_ci cbs = DIV_ROUND_UP(cbs, 4096); 3462306a36Sopenharmony_ci /* Avoid using zero burst */ 3562306a36Sopenharmony_ci cbs = cbs ?: 1; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* Check that actually the result can be written */ 3862306a36Sopenharmony_ci if (cir > GENMASK(15, 0) || 3962306a36Sopenharmony_ci cbs > GENMASK(6, 0)) 4062306a36Sopenharmony_ci return -EINVAL; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | 4362306a36Sopenharmony_ci QSYS_SE_CFG_SE_FRM_MODE_SET(1), 4462306a36Sopenharmony_ci QSYS_SE_CFG_SE_AVB_ENA | 4562306a36Sopenharmony_ci QSYS_SE_CFG_SE_FRM_MODE, 4662306a36Sopenharmony_ci lan966x, QSYS_SE_CFG(se_idx)); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(cir) | 4962306a36Sopenharmony_ci QSYS_CIR_CFG_CIR_BURST_SET(cbs), 5062306a36Sopenharmony_ci lan966x, QSYS_CIR_CFG(se_idx)); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciint lan966x_tbf_del(struct lan966x_port *port, 5662306a36Sopenharmony_ci struct tc_tbf_qopt_offload *qopt) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct lan966x *lan966x = port->lan966x; 5962306a36Sopenharmony_ci bool root = qopt->parent == TC_H_ROOT; 6062306a36Sopenharmony_ci u32 queue = 0; 6162306a36Sopenharmony_ci u32 se_idx; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (!root) { 6462306a36Sopenharmony_ci queue = TC_H_MIN(qopt->parent) - 1; 6562306a36Sopenharmony_ci if (queue >= NUM_PRIO_QUEUES) 6662306a36Sopenharmony_ci return -EOPNOTSUPP; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (root) 7062306a36Sopenharmony_ci se_idx = SE_IDX_PORT + port->chip_port; 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | 7562306a36Sopenharmony_ci QSYS_SE_CFG_SE_FRM_MODE_SET(0), 7662306a36Sopenharmony_ci QSYS_SE_CFG_SE_AVB_ENA | 7762306a36Sopenharmony_ci QSYS_SE_CFG_SE_FRM_MODE, 7862306a36Sopenharmony_ci lan966x, QSYS_SE_CFG(se_idx)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(0) | 8162306a36Sopenharmony_ci QSYS_CIR_CFG_CIR_BURST_SET(0), 8262306a36Sopenharmony_ci lan966x, QSYS_CIR_CFG(se_idx)); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 86