| // SPDX-License-Identifier: GPL-2.0+ |
| |
| #include "lan966x_main.h" |
| |
| int lan966x_cbs_add(struct lan966x_port *port, |
| struct tc_cbs_qopt_offload *qopt) |
| { |
| struct lan966x *lan966x = port->lan966x; |
| u32 cir, cbs; |
| u8 se_idx; |
| |
| /* Check for invalid values */ |
| if (qopt->idleslope <= 0 || |
| qopt->sendslope >= 0 || |
| qopt->locredit >= qopt->hicredit) |
| return -EINVAL; |
| |
| se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + qopt->queue; |
| cir = qopt->idleslope; |
| cbs = (qopt->idleslope - qopt->sendslope) * |
| (qopt->hicredit - qopt->locredit) / |
| -qopt->sendslope; |
| |
| /* 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(1) | |
| 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_cbs_del(struct lan966x_port *port, |
| struct tc_cbs_qopt_offload *qopt) |
| { |
| struct lan966x *lan966x = port->lan966x; |
| u8 se_idx; |
| |
| se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + qopt->queue; |
| |
| lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(1) | |
| 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; |
| } |