// SPDX-License-Identifier: GPL-2.0+ #include "lan966x_main.h" int lan966x_tbf_add(struct lan966x_port *port, struct tc_tbf_qopt_offload *qopt) { struct lan966x *lan966x = port->lan966x; bool root = qopt->parent == TC_H_ROOT; u32 queue = 0; u32 cir, cbs; u32 se_idx; if (!root) { queue = TC_H_MIN(qopt->parent) - 1; if (queue >= NUM_PRIO_QUEUES) return -EOPNOTSUPP; } if (root) se_idx = SE_IDX_PORT + port->chip_port; else se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; cir = div_u64(qopt->replace_params.rate.rate_bytes_ps, 1000) * 8; cbs = qopt->replace_params.max_size; /* Rate unit is 100 kbps */ cir = DIV_ROUND_UP(cir, 100); /* Avoid using zero rate */ cir = cir ?: 1; /* Burst unit is 4kB */ cbs = DIV_ROUND_UP(cbs, 4096); /* Avoid using zero burst */ cbs = cbs ?: 1; /* Check that actually the result can be written */ if (cir > GENMASK(15, 0) || cbs > GENMASK(6, 0)) return -EINVAL; lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | QSYS_SE_CFG_SE_FRM_MODE_SET(1), QSYS_SE_CFG_SE_AVB_ENA | QSYS_SE_CFG_SE_FRM_MODE, lan966x, QSYS_SE_CFG(se_idx)); lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(cir) | QSYS_CIR_CFG_CIR_BURST_SET(cbs), lan966x, QSYS_CIR_CFG(se_idx)); return 0; } int lan966x_tbf_del(struct lan966x_port *port, struct tc_tbf_qopt_offload *qopt) { struct lan966x *lan966x = port->lan966x; bool root = qopt->parent == TC_H_ROOT; u32 queue = 0; u32 se_idx; if (!root) { queue = TC_H_MIN(qopt->parent) - 1; if (queue >= NUM_PRIO_QUEUES) return -EOPNOTSUPP; } if (root) se_idx = SE_IDX_PORT + port->chip_port; else se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | QSYS_SE_CFG_SE_FRM_MODE_SET(0), QSYS_SE_CFG_SE_AVB_ENA | QSYS_SE_CFG_SE_FRM_MODE, lan966x, QSYS_SE_CFG(se_idx)); lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(0) | QSYS_CIR_CFG_CIR_BURST_SET(0), lan966x, QSYS_CIR_CFG(se_idx)); return 0; }