Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'lan966x-qos'

Horatiu Vultur says:

====================
net: lan966x: Add tbf, cbs, ets support

Add support for offloading QoS features with tc command to lan966x.
The offloaded Qos features are tbf, cbs and ets.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+365 -1
+2 -1
drivers/net/ethernet/microchip/lan966x/Makefile
··· 9 9 lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \ 10 10 lan966x_vlan.o lan966x_fdb.o lan966x_mdb.o \ 11 11 lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \ 12 - lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o 12 + lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \ 13 + lan966x_tbf.o lan966x_cbs.o lan966x_ets.o
+70
drivers/net/ethernet/microchip/lan966x/lan966x_cbs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include "lan966x_main.h" 4 + 5 + int lan966x_cbs_add(struct lan966x_port *port, 6 + struct tc_cbs_qopt_offload *qopt) 7 + { 8 + struct lan966x *lan966x = port->lan966x; 9 + u32 cir, cbs; 10 + u8 se_idx; 11 + 12 + /* Check for invalid values */ 13 + if (qopt->idleslope <= 0 || 14 + qopt->sendslope >= 0 || 15 + qopt->locredit >= qopt->hicredit) 16 + return -EINVAL; 17 + 18 + se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + qopt->queue; 19 + cir = qopt->idleslope; 20 + cbs = (qopt->idleslope - qopt->sendslope) * 21 + (qopt->hicredit - qopt->locredit) / 22 + -qopt->sendslope; 23 + 24 + /* Rate unit is 100 kbps */ 25 + cir = DIV_ROUND_UP(cir, 100); 26 + /* Avoid using zero rate */ 27 + cir = cir ?: 1; 28 + /* Burst unit is 4kB */ 29 + cbs = DIV_ROUND_UP(cbs, 4096); 30 + /* Avoid using zero burst */ 31 + cbs = cbs ?: 1; 32 + 33 + /* Check that actually the result can be written */ 34 + if (cir > GENMASK(15, 0) || 35 + cbs > GENMASK(6, 0)) 36 + return -EINVAL; 37 + 38 + lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(1) | 39 + QSYS_SE_CFG_SE_FRM_MODE_SET(1), 40 + QSYS_SE_CFG_SE_AVB_ENA | 41 + QSYS_SE_CFG_SE_FRM_MODE, 42 + lan966x, QSYS_SE_CFG(se_idx)); 43 + 44 + lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(cir) | 45 + QSYS_CIR_CFG_CIR_BURST_SET(cbs), 46 + lan966x, QSYS_CIR_CFG(se_idx)); 47 + 48 + return 0; 49 + } 50 + 51 + int lan966x_cbs_del(struct lan966x_port *port, 52 + struct tc_cbs_qopt_offload *qopt) 53 + { 54 + struct lan966x *lan966x = port->lan966x; 55 + u8 se_idx; 56 + 57 + se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + qopt->queue; 58 + 59 + lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(1) | 60 + QSYS_SE_CFG_SE_FRM_MODE_SET(0), 61 + QSYS_SE_CFG_SE_AVB_ENA | 62 + QSYS_SE_CFG_SE_FRM_MODE, 63 + lan966x, QSYS_SE_CFG(se_idx)); 64 + 65 + lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(0) | 66 + QSYS_CIR_CFG_CIR_BURST_SET(0), 67 + lan966x, QSYS_CIR_CFG(se_idx)); 68 + 69 + return 0; 70 + }
+96
drivers/net/ethernet/microchip/lan966x/lan966x_ets.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include "lan966x_main.h" 4 + 5 + #define DWRR_COST_BIT_WIDTH BIT(5) 6 + 7 + static u32 lan966x_ets_hw_cost(u32 w_min, u32 weight) 8 + { 9 + u32 res; 10 + 11 + /* Round half up: Multiply with 16 before division, 12 + * add 8 and divide result with 16 again 13 + */ 14 + res = (((DWRR_COST_BIT_WIDTH << 4) * w_min / weight) + 8) >> 4; 15 + return max_t(u32, 1, res) - 1; 16 + } 17 + 18 + int lan966x_ets_add(struct lan966x_port *port, 19 + struct tc_ets_qopt_offload *qopt) 20 + { 21 + struct tc_ets_qopt_offload_replace_params *params; 22 + struct lan966x *lan966x = port->lan966x; 23 + u32 w_min = 100; 24 + u8 count = 0; 25 + u32 se_idx; 26 + u8 i; 27 + 28 + /* Check the input */ 29 + if (qopt->parent != TC_H_ROOT) 30 + return -EINVAL; 31 + 32 + params = &qopt->replace_params; 33 + if (params->bands != NUM_PRIO_QUEUES) 34 + return -EINVAL; 35 + 36 + for (i = 0; i < params->bands; ++i) { 37 + /* In the switch the DWRR is always on the lowest consecutive 38 + * priorities. Due to this, the first priority must map to the 39 + * first DWRR band. 40 + */ 41 + if (params->priomap[i] != (7 - i)) 42 + return -EINVAL; 43 + 44 + if (params->quanta[i] && params->weights[i] == 0) 45 + return -EINVAL; 46 + } 47 + 48 + se_idx = SE_IDX_PORT + port->chip_port; 49 + 50 + /* Find minimum weight */ 51 + for (i = 0; i < params->bands; ++i) { 52 + if (params->quanta[i] == 0) 53 + continue; 54 + 55 + w_min = min(w_min, params->weights[i]); 56 + } 57 + 58 + for (i = 0; i < params->bands; ++i) { 59 + if (params->quanta[i] == 0) 60 + continue; 61 + 62 + ++count; 63 + 64 + lan_wr(lan966x_ets_hw_cost(w_min, params->weights[i]), 65 + lan966x, QSYS_SE_DWRR_CFG(se_idx, 7 - i)); 66 + } 67 + 68 + lan_rmw(QSYS_SE_CFG_SE_DWRR_CNT_SET(count) | 69 + QSYS_SE_CFG_SE_RR_ENA_SET(0), 70 + QSYS_SE_CFG_SE_DWRR_CNT | 71 + QSYS_SE_CFG_SE_RR_ENA, 72 + lan966x, QSYS_SE_CFG(se_idx)); 73 + 74 + return 0; 75 + } 76 + 77 + int lan966x_ets_del(struct lan966x_port *port, 78 + struct tc_ets_qopt_offload *qopt) 79 + { 80 + struct lan966x *lan966x = port->lan966x; 81 + u32 se_idx; 82 + int i; 83 + 84 + se_idx = SE_IDX_PORT + port->chip_port; 85 + 86 + for (i = 0; i < NUM_PRIO_QUEUES; ++i) 87 + lan_wr(0, lan966x, QSYS_SE_DWRR_CFG(se_idx, i)); 88 + 89 + lan_rmw(QSYS_SE_CFG_SE_DWRR_CNT_SET(0) | 90 + QSYS_SE_CFG_SE_RR_ENA_SET(0), 91 + QSYS_SE_CFG_SE_DWRR_CNT | 92 + QSYS_SE_CFG_SE_RR_ENA, 93 + lan966x, QSYS_SE_CFG(se_idx)); 94 + 95 + return 0; 96 + }
+19
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
··· 9 9 #include <linux/phy.h> 10 10 #include <linux/phylink.h> 11 11 #include <linux/ptp_clock_kernel.h> 12 + #include <net/pkt_cls.h> 12 13 #include <net/pkt_sched.h> 13 14 #include <net/switchdev.h> 14 15 ··· 81 80 #define FDMA_XTR_CHANNEL 6 82 81 #define FDMA_INJ_CHANNEL 0 83 82 #define FDMA_DCB_MAX 512 83 + 84 + #define SE_IDX_QUEUE 0 /* 0-79 : Queue scheduler elements */ 85 + #define SE_IDX_PORT 80 /* 80-89 : Port schedular elements */ 84 86 85 87 /* MAC table entry types. 86 88 * ENTRYTYPE_NORMAL is subject to aging. ··· 465 461 struct tc_taprio_qopt_offload *qopt); 466 462 int lan966x_taprio_del(struct lan966x_port *port); 467 463 int lan966x_taprio_speed_set(struct lan966x_port *port, int speed); 464 + 465 + int lan966x_tbf_add(struct lan966x_port *port, 466 + struct tc_tbf_qopt_offload *qopt); 467 + int lan966x_tbf_del(struct lan966x_port *port, 468 + struct tc_tbf_qopt_offload *qopt); 469 + 470 + int lan966x_cbs_add(struct lan966x_port *port, 471 + struct tc_cbs_qopt_offload *qopt); 472 + int lan966x_cbs_del(struct lan966x_port *port, 473 + struct tc_cbs_qopt_offload *qopt); 474 + 475 + int lan966x_ets_add(struct lan966x_port *port, 476 + struct tc_ets_qopt_offload *qopt); 477 + int lan966x_ets_del(struct lan966x_port *port, 478 + struct tc_ets_qopt_offload *qopt); 468 479 469 480 static inline void __iomem *lan_addr(void __iomem *base[], 470 481 int id, int tinst, int tcnt,
+50
drivers/net/ethernet/microchip/lan966x/lan966x_regs.h
··· 1018 1018 /* QSYS:RES_CTRL:RES_CFG */ 1019 1019 #define QSYS_RES_CFG(g) __REG(TARGET_QSYS, 0, 1, 32768, g, 1024, 8, 0, 0, 1, 4) 1020 1020 1021 + /* QSYS:HSCH:CIR_CFG */ 1022 + #define QSYS_CIR_CFG(g) __REG(TARGET_QSYS, 0, 1, 16384, g, 90, 128, 0, 0, 1, 4) 1023 + 1024 + #define QSYS_CIR_CFG_CIR_RATE GENMASK(20, 6) 1025 + #define QSYS_CIR_CFG_CIR_RATE_SET(x)\ 1026 + FIELD_PREP(QSYS_CIR_CFG_CIR_RATE, x) 1027 + #define QSYS_CIR_CFG_CIR_RATE_GET(x)\ 1028 + FIELD_GET(QSYS_CIR_CFG_CIR_RATE, x) 1029 + 1030 + #define QSYS_CIR_CFG_CIR_BURST GENMASK(5, 0) 1031 + #define QSYS_CIR_CFG_CIR_BURST_SET(x)\ 1032 + FIELD_PREP(QSYS_CIR_CFG_CIR_BURST, x) 1033 + #define QSYS_CIR_CFG_CIR_BURST_GET(x)\ 1034 + FIELD_GET(QSYS_CIR_CFG_CIR_BURST, x) 1035 + 1036 + /* QSYS:HSCH:SE_CFG */ 1037 + #define QSYS_SE_CFG(g) __REG(TARGET_QSYS, 0, 1, 16384, g, 90, 128, 8, 0, 1, 4) 1038 + 1039 + #define QSYS_SE_CFG_SE_DWRR_CNT GENMASK(9, 6) 1040 + #define QSYS_SE_CFG_SE_DWRR_CNT_SET(x)\ 1041 + FIELD_PREP(QSYS_SE_CFG_SE_DWRR_CNT, x) 1042 + #define QSYS_SE_CFG_SE_DWRR_CNT_GET(x)\ 1043 + FIELD_GET(QSYS_SE_CFG_SE_DWRR_CNT, x) 1044 + 1045 + #define QSYS_SE_CFG_SE_RR_ENA BIT(5) 1046 + #define QSYS_SE_CFG_SE_RR_ENA_SET(x)\ 1047 + FIELD_PREP(QSYS_SE_CFG_SE_RR_ENA, x) 1048 + #define QSYS_SE_CFG_SE_RR_ENA_GET(x)\ 1049 + FIELD_GET(QSYS_SE_CFG_SE_RR_ENA, x) 1050 + 1051 + #define QSYS_SE_CFG_SE_AVB_ENA BIT(4) 1052 + #define QSYS_SE_CFG_SE_AVB_ENA_SET(x)\ 1053 + FIELD_PREP(QSYS_SE_CFG_SE_AVB_ENA, x) 1054 + #define QSYS_SE_CFG_SE_AVB_ENA_GET(x)\ 1055 + FIELD_GET(QSYS_SE_CFG_SE_AVB_ENA, x) 1056 + 1057 + #define QSYS_SE_CFG_SE_FRM_MODE GENMASK(3, 2) 1058 + #define QSYS_SE_CFG_SE_FRM_MODE_SET(x)\ 1059 + FIELD_PREP(QSYS_SE_CFG_SE_FRM_MODE, x) 1060 + #define QSYS_SE_CFG_SE_FRM_MODE_GET(x)\ 1061 + FIELD_GET(QSYS_SE_CFG_SE_FRM_MODE, x) 1062 + 1063 + #define QSYS_SE_DWRR_CFG(g, r) __REG(TARGET_QSYS, 0, 1, 16384, g, 90, 128, 12, r, 12, 4) 1064 + 1065 + #define QSYS_SE_DWRR_CFG_DWRR_COST GENMASK(4, 0) 1066 + #define QSYS_SE_DWRR_CFG_DWRR_COST_SET(x)\ 1067 + FIELD_PREP(QSYS_SE_DWRR_CFG_DWRR_COST, x) 1068 + #define QSYS_SE_DWRR_CFG_DWRR_COST_GET(x)\ 1069 + FIELD_GET(QSYS_SE_DWRR_CFG_DWRR_COST, x) 1070 + 1021 1071 /* QSYS:TAS_CONFIG:TAS_CFG_CTRL */ 1022 1072 #define QSYS_TAS_CFG_CTRL __REG(TARGET_QSYS, 0, 1, 57372, 0, 1, 12, 0, 0, 1, 4) 1023 1073
+85
drivers/net/ethernet/microchip/lan966x/lan966x_tbf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + #include "lan966x_main.h" 4 + 5 + int lan966x_tbf_add(struct lan966x_port *port, 6 + struct tc_tbf_qopt_offload *qopt) 7 + { 8 + struct lan966x *lan966x = port->lan966x; 9 + bool root = qopt->parent == TC_H_ROOT; 10 + u32 queue = 0; 11 + u32 cir, cbs; 12 + u32 se_idx; 13 + 14 + if (!root) { 15 + queue = TC_H_MIN(qopt->parent) - 1; 16 + if (queue >= NUM_PRIO_QUEUES) 17 + return -EOPNOTSUPP; 18 + } 19 + 20 + if (root) 21 + se_idx = SE_IDX_PORT + port->chip_port; 22 + else 23 + se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; 24 + 25 + cir = div_u64(qopt->replace_params.rate.rate_bytes_ps, 1000) * 8; 26 + cbs = qopt->replace_params.max_size; 27 + 28 + /* Rate unit is 100 kbps */ 29 + cir = DIV_ROUND_UP(cir, 100); 30 + /* Avoid using zero rate */ 31 + cir = cir ?: 1; 32 + /* Burst unit is 4kB */ 33 + cbs = DIV_ROUND_UP(cbs, 4096); 34 + /* Avoid using zero burst */ 35 + cbs = cbs ?: 1; 36 + 37 + /* Check that actually the result can be written */ 38 + if (cir > GENMASK(15, 0) || 39 + cbs > GENMASK(6, 0)) 40 + return -EINVAL; 41 + 42 + lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | 43 + QSYS_SE_CFG_SE_FRM_MODE_SET(1), 44 + QSYS_SE_CFG_SE_AVB_ENA | 45 + QSYS_SE_CFG_SE_FRM_MODE, 46 + lan966x, QSYS_SE_CFG(se_idx)); 47 + 48 + lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(cir) | 49 + QSYS_CIR_CFG_CIR_BURST_SET(cbs), 50 + lan966x, QSYS_CIR_CFG(se_idx)); 51 + 52 + return 0; 53 + } 54 + 55 + int lan966x_tbf_del(struct lan966x_port *port, 56 + struct tc_tbf_qopt_offload *qopt) 57 + { 58 + struct lan966x *lan966x = port->lan966x; 59 + bool root = qopt->parent == TC_H_ROOT; 60 + u32 queue = 0; 61 + u32 se_idx; 62 + 63 + if (!root) { 64 + queue = TC_H_MIN(qopt->parent) - 1; 65 + if (queue >= NUM_PRIO_QUEUES) 66 + return -EOPNOTSUPP; 67 + } 68 + 69 + if (root) 70 + se_idx = SE_IDX_PORT + port->chip_port; 71 + else 72 + se_idx = SE_IDX_QUEUE + port->chip_port * NUM_PRIO_QUEUES + queue; 73 + 74 + lan_rmw(QSYS_SE_CFG_SE_AVB_ENA_SET(0) | 75 + QSYS_SE_CFG_SE_FRM_MODE_SET(0), 76 + QSYS_SE_CFG_SE_AVB_ENA | 77 + QSYS_SE_CFG_SE_FRM_MODE, 78 + lan966x, QSYS_SE_CFG(se_idx)); 79 + 80 + lan_wr(QSYS_CIR_CFG_CIR_RATE_SET(0) | 81 + QSYS_CIR_CFG_CIR_BURST_SET(0), 82 + lan966x, QSYS_CIR_CFG(se_idx)); 83 + 84 + return 0; 85 + }
+43
drivers/net/ethernet/microchip/lan966x/lan966x_tc.c
··· 22 22 lan966x_taprio_del(port); 23 23 } 24 24 25 + static int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port, 26 + struct tc_tbf_qopt_offload *qopt) 27 + { 28 + switch (qopt->command) { 29 + case TC_TBF_REPLACE: 30 + return lan966x_tbf_add(port, qopt); 31 + case TC_TBF_DESTROY: 32 + return lan966x_tbf_del(port, qopt); 33 + default: 34 + return -EOPNOTSUPP; 35 + } 36 + 37 + return -EOPNOTSUPP; 38 + } 39 + 40 + static int lan966x_tc_setup_qdisc_cbs(struct lan966x_port *port, 41 + struct tc_cbs_qopt_offload *qopt) 42 + { 43 + return qopt->enable ? lan966x_cbs_add(port, qopt) : 44 + lan966x_cbs_del(port, qopt); 45 + } 46 + 47 + static int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port, 48 + struct tc_ets_qopt_offload *qopt) 49 + { 50 + switch (qopt->command) { 51 + case TC_ETS_REPLACE: 52 + return lan966x_ets_add(port, qopt); 53 + case TC_ETS_DESTROY: 54 + return lan966x_ets_del(port, qopt); 55 + default: 56 + return -EOPNOTSUPP; 57 + }; 58 + 59 + return -EOPNOTSUPP; 60 + } 61 + 25 62 int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type, 26 63 void *type_data) 27 64 { ··· 69 32 return lan966x_tc_setup_qdisc_mqprio(port, type_data); 70 33 case TC_SETUP_QDISC_TAPRIO: 71 34 return lan966x_tc_setup_qdisc_taprio(port, type_data); 35 + case TC_SETUP_QDISC_TBF: 36 + return lan966x_tc_setup_qdisc_tbf(port, type_data); 37 + case TC_SETUP_QDISC_CBS: 38 + return lan966x_tc_setup_qdisc_cbs(port, type_data); 39 + case TC_SETUP_QDISC_ETS: 40 + return lan966x_tc_setup_qdisc_ets(port, type_data); 72 41 default: 73 42 return -EOPNOTSUPP; 74 43 }