|
17 | 17 |
|
18 | 18 | #define AM65_CPSW_REG_CTL 0x004 |
19 | 19 | #define AM65_CPSW_PN_REG_CTL 0x004 |
20 | | -#define AM65_CPSW_PN_REG_TX_PRI_MAP 0x018 |
21 | | -#define AM65_CPSW_PN_REG_RX_PRI_MAP 0x020 |
22 | 20 | #define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 |
23 | 21 | #define AM65_CPSW_PN_REG_EST_CTL 0x060 |
24 | 22 | #define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri)) |
25 | | -#define AM65_CPSW_PN_REG_PRI_EIR(pri) (0x160 + 4 * (pri)) |
26 | 23 |
|
27 | 24 | /* AM65_CPSW_REG_CTL register fields */ |
28 | 25 | #define AM65_CPSW_CTL_EST_EN BIT(18) |
@@ -59,12 +56,6 @@ enum timer_act { |
59 | 56 | TACT_SKIP_PROG, /* just buffer can be updated */ |
60 | 57 | }; |
61 | 58 |
|
62 | | -/* number of traffic classes (FIFOs) per port */ |
63 | | -#define AM65_CPSW_PN_TC_NUM 8 |
64 | | -#define AM65_CPSW_PN_TX_PRI_MAP_DEFAULT 0x76543210 |
65 | | - |
66 | | -static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data); |
67 | | - |
68 | 59 | static int am65_cpsw_port_est_enabled(struct am65_cpsw_port *port) |
69 | 60 | { |
70 | 61 | return port->qos.est_oper || port->qos.est_admin; |
@@ -550,6 +541,7 @@ static void am65_cpsw_est_link_up(struct net_device *ndev, int link_speed) |
550 | 541 | ktime_t cur_time; |
551 | 542 | s64 delta; |
552 | 543 |
|
| 544 | + port->qos.link_speed = link_speed; |
553 | 545 | if (!am65_cpsw_port_est_enabled(port)) |
554 | 546 | return; |
555 | 547 |
|
@@ -803,24 +795,17 @@ int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, |
803 | 795 | return am65_cpsw_tc_query_caps(ndev, type_data); |
804 | 796 | case TC_SETUP_QDISC_TAPRIO: |
805 | 797 | return am65_cpsw_setup_taprio(ndev, type_data); |
806 | | - case TC_SETUP_QDISC_MQPRIO: |
807 | | - return am65_cpsw_setup_mqprio(ndev, type_data); |
808 | 798 | case TC_SETUP_BLOCK: |
809 | 799 | return am65_cpsw_qos_setup_tc_block(ndev, type_data); |
810 | 800 | default: |
811 | 801 | return -EOPNOTSUPP; |
812 | 802 | } |
813 | 803 | } |
814 | 804 |
|
815 | | -static void am65_cpsw_tx_pn_shaper_link_up(struct am65_cpsw_port *port); |
816 | | - |
817 | 805 | void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed) |
818 | 806 | { |
819 | 807 | struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
820 | 808 |
|
821 | | - port->qos.link_speed = link_speed; |
822 | | - am65_cpsw_tx_pn_shaper_link_up(port); |
823 | | - |
824 | 809 | if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) |
825 | 810 | return; |
826 | 811 |
|
@@ -952,281 +937,3 @@ void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common) |
952 | 937 | host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch)); |
953 | 938 | } |
954 | 939 | } |
955 | | - |
956 | | -static void am65_cpsw_tx_pn_shaper_apply(struct am65_cpsw_port *port) |
957 | | -{ |
958 | | - struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; |
959 | | - struct am65_cpsw_common *common = port->common; |
960 | | - struct tc_mqprio_qopt_offload *mqprio; |
961 | | - bool shaper_en; |
962 | | - u32 rate_mbps; |
963 | | - int i; |
964 | | - |
965 | | - mqprio = &p_mqprio->mqprio_hw; |
966 | | - shaper_en = p_mqprio->shaper_en && !p_mqprio->shaper_susp; |
967 | | - |
968 | | - for (i = 0; i < mqprio->qopt.num_tc; i++) { |
969 | | - rate_mbps = 0; |
970 | | - if (shaper_en) { |
971 | | - rate_mbps = mqprio->min_rate[i] * 8 / 1000000; |
972 | | - rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps, |
973 | | - common->bus_freq); |
974 | | - } |
975 | | - |
976 | | - writel(rate_mbps, |
977 | | - port->port_base + AM65_CPSW_PN_REG_PRI_CIR(i)); |
978 | | - } |
979 | | - |
980 | | - for (i = 0; i < mqprio->qopt.num_tc; i++) { |
981 | | - rate_mbps = 0; |
982 | | - if (shaper_en && mqprio->max_rate[i]) { |
983 | | - rate_mbps = mqprio->max_rate[i] - mqprio->min_rate[i]; |
984 | | - rate_mbps = rate_mbps * 8 / 1000000; |
985 | | - rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps, |
986 | | - common->bus_freq); |
987 | | - } |
988 | | - |
989 | | - writel(rate_mbps, |
990 | | - port->port_base + AM65_CPSW_PN_REG_PRI_EIR(i)); |
991 | | - } |
992 | | -} |
993 | | - |
994 | | -static void am65_cpsw_tx_pn_shaper_link_up(struct am65_cpsw_port *port) |
995 | | -{ |
996 | | - struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; |
997 | | - struct am65_cpsw_common *common = port->common; |
998 | | - bool shaper_susp = false; |
999 | | - |
1000 | | - if (!p_mqprio->enable || !p_mqprio->shaper_en) |
1001 | | - return; |
1002 | | - |
1003 | | - if (p_mqprio->max_rate_total > port->qos.link_speed) |
1004 | | - shaper_susp = true; |
1005 | | - |
1006 | | - if (p_mqprio->shaper_susp == shaper_susp) |
1007 | | - return; |
1008 | | - |
1009 | | - if (shaper_susp) |
1010 | | - dev_info(common->dev, |
1011 | | - "Port%u: total shaper tx rate > link speed - suspend shaper\n", |
1012 | | - port->port_id); |
1013 | | - else |
1014 | | - dev_info(common->dev, |
1015 | | - "Port%u: link recover - resume shaper\n", |
1016 | | - port->port_id); |
1017 | | - |
1018 | | - p_mqprio->shaper_susp = shaper_susp; |
1019 | | - am65_cpsw_tx_pn_shaper_apply(port); |
1020 | | -} |
1021 | | - |
1022 | | -void am65_cpsw_qos_mqprio_init(struct am65_cpsw_port *port) |
1023 | | -{ |
1024 | | - struct am65_cpsw_host *host = am65_common_get_host(port->common); |
1025 | | - struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio; |
1026 | | - struct tc_mqprio_qopt_offload *mqprio; |
1027 | | - u32 tx_prio_map = 0, rx_prio_map; |
1028 | | - int i, fifo; |
1029 | | - |
1030 | | - mqprio = &p_mqprio->mqprio_hw; |
1031 | | - rx_prio_map = readl(host->port_base + AM65_CPSW_PN_REG_RX_PRI_MAP); |
1032 | | - |
1033 | | - if (p_mqprio->enable) { |
1034 | | - for (i = 0; i < AM65_CPSW_PN_TC_NUM; i++) { |
1035 | | - fifo = mqprio->qopt.prio_tc_map[i]; |
1036 | | - tx_prio_map |= fifo << (4 * i); |
1037 | | - } |
1038 | | - |
1039 | | - netdev_set_num_tc(port->ndev, mqprio->qopt.num_tc); |
1040 | | - for (i = 0; i < mqprio->qopt.num_tc; i++) { |
1041 | | - netdev_set_tc_queue(port->ndev, i, |
1042 | | - mqprio->qopt.count[i], |
1043 | | - mqprio->qopt.offset[i]); |
1044 | | - if (!i) { |
1045 | | - p_mqprio->tc0_q = mqprio->qopt.offset[i]; |
1046 | | - rx_prio_map &= ~(0x7 << (4 * p_mqprio->tc0_q)); |
1047 | | - } |
1048 | | - } |
1049 | | - } else { |
1050 | | - /* restore default configuration */ |
1051 | | - netdev_reset_tc(port->ndev); |
1052 | | - tx_prio_map = AM65_CPSW_PN_TX_PRI_MAP_DEFAULT; |
1053 | | - rx_prio_map |= p_mqprio->tc0_q << (4 * p_mqprio->tc0_q); |
1054 | | - p_mqprio->tc0_q = 0; |
1055 | | - } |
1056 | | - |
1057 | | - writel(tx_prio_map, |
1058 | | - port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP); |
1059 | | - writel(rx_prio_map, |
1060 | | - host->port_base + AM65_CPSW_PN_REG_RX_PRI_MAP); |
1061 | | - |
1062 | | - am65_cpsw_tx_pn_shaper_apply(port); |
1063 | | -} |
1064 | | - |
1065 | | -static int am65_cpsw_mqprio_verify(struct am65_cpsw_port *port, |
1066 | | - struct tc_mqprio_qopt_offload *mqprio) |
1067 | | -{ |
1068 | | - int i; |
1069 | | - |
1070 | | - for (i = 0; i < mqprio->qopt.num_tc; i++) { |
1071 | | - unsigned int last = mqprio->qopt.offset[i] + |
1072 | | - mqprio->qopt.count[i]; |
1073 | | - |
1074 | | - if (mqprio->qopt.offset[i] >= port->ndev->real_num_tx_queues || |
1075 | | - !mqprio->qopt.count[i] || |
1076 | | - last > port->ndev->real_num_tx_queues) |
1077 | | - return -EINVAL; |
1078 | | - } |
1079 | | - |
1080 | | - return 0; |
1081 | | -} |
1082 | | - |
1083 | | -static int am65_cpsw_mqprio_verify_shaper(struct am65_cpsw_port *port, |
1084 | | - struct tc_mqprio_qopt_offload *mqprio, |
1085 | | - u64 *max_rate) |
1086 | | -{ |
1087 | | - struct am65_cpsw_common *common = port->common; |
1088 | | - u64 min_rate_total = 0, max_rate_total = 0; |
1089 | | - u32 min_rate_msk = 0, max_rate_msk = 0; |
1090 | | - bool has_min_rate, has_max_rate; |
1091 | | - int num_tc, i; |
1092 | | - |
1093 | | - has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE); |
1094 | | - has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE); |
1095 | | - |
1096 | | - if (!has_min_rate && has_max_rate) |
1097 | | - return -EOPNOTSUPP; |
1098 | | - |
1099 | | - if (!has_min_rate) |
1100 | | - return 0; |
1101 | | - |
1102 | | - num_tc = mqprio->qopt.num_tc; |
1103 | | - |
1104 | | - for (i = num_tc - 1; i >= 0; i--) { |
1105 | | - u32 ch_msk; |
1106 | | - |
1107 | | - if (mqprio->min_rate[i]) |
1108 | | - min_rate_msk |= BIT(i); |
1109 | | - min_rate_total += mqprio->min_rate[i]; |
1110 | | - |
1111 | | - if (has_max_rate) { |
1112 | | - if (mqprio->max_rate[i]) |
1113 | | - max_rate_msk |= BIT(i); |
1114 | | - max_rate_total += mqprio->max_rate[i]; |
1115 | | - |
1116 | | - if (!mqprio->min_rate[i] && mqprio->max_rate[i]) { |
1117 | | - dev_err(common->dev, "TX tc%d rate max>0 but min=0\n", |
1118 | | - i); |
1119 | | - return -EINVAL; |
1120 | | - } |
1121 | | - |
1122 | | - if (mqprio->max_rate[i] && |
1123 | | - mqprio->max_rate[i] < mqprio->min_rate[i]) { |
1124 | | - dev_err(common->dev, "TX tc%d rate min(%llu)>max(%llu)\n", |
1125 | | - i, mqprio->min_rate[i], |
1126 | | - mqprio->max_rate[i]); |
1127 | | - return -EINVAL; |
1128 | | - } |
1129 | | - } |
1130 | | - |
1131 | | - ch_msk = GENMASK(num_tc - 1, i); |
1132 | | - if ((min_rate_msk & BIT(i)) && (min_rate_msk ^ ch_msk)) { |
1133 | | - dev_err(common->dev, "TX Min rate limiting has to be enabled sequentially hi->lo tx_rate_msk%x\n", |
1134 | | - min_rate_msk); |
1135 | | - return -EINVAL; |
1136 | | - } |
1137 | | - |
1138 | | - if ((max_rate_msk & BIT(i)) && (max_rate_msk ^ ch_msk)) { |
1139 | | - dev_err(common->dev, "TX max rate limiting has to be enabled sequentially hi->lo tx_rate_msk%x\n", |
1140 | | - max_rate_msk); |
1141 | | - return -EINVAL; |
1142 | | - } |
1143 | | - } |
1144 | | - min_rate_total *= 8; |
1145 | | - min_rate_total /= 1000 * 1000; |
1146 | | - max_rate_total *= 8; |
1147 | | - max_rate_total /= 1000 * 1000; |
1148 | | - |
1149 | | - if (port->qos.link_speed != SPEED_UNKNOWN) { |
1150 | | - if (min_rate_total > port->qos.link_speed) { |
1151 | | - dev_err(common->dev, "TX rate min exceed %llu link speed %d\n", |
1152 | | - min_rate_total, port->qos.link_speed); |
1153 | | - return -EINVAL; |
1154 | | - } |
1155 | | - |
1156 | | - if (max_rate_total > port->qos.link_speed) { |
1157 | | - dev_err(common->dev, "TX rate max exceed %llu link speed %d\n", |
1158 | | - max_rate_total, port->qos.link_speed); |
1159 | | - return -EINVAL; |
1160 | | - } |
1161 | | - } |
1162 | | - |
1163 | | - *max_rate = max_t(u64, min_rate_total, max_rate_total); |
1164 | | - |
1165 | | - return 0; |
1166 | | -} |
1167 | | - |
1168 | | -static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data) |
1169 | | -{ |
1170 | | - struct am65_cpsw_port *port = am65_ndev_to_port(ndev); |
1171 | | - struct tc_mqprio_qopt_offload *mqprio = type_data; |
1172 | | - struct am65_cpsw_common *common = port->common; |
1173 | | - struct am65_cpsw_mqprio *p_mqprio; |
1174 | | - bool has_min_rate; |
1175 | | - int num_tc, ret; |
1176 | | - u64 max_rate; |
1177 | | - |
1178 | | - p_mqprio = &port->qos.mqprio; |
1179 | | - |
1180 | | - if (!mqprio->qopt.hw) |
1181 | | - goto skip_check; |
1182 | | - |
1183 | | - if (mqprio->mode != TC_MQPRIO_MODE_CHANNEL) |
1184 | | - return -EOPNOTSUPP; |
1185 | | - |
1186 | | - num_tc = mqprio->qopt.num_tc; |
1187 | | - if (num_tc > AM65_CPSW_PN_TC_NUM) |
1188 | | - return -ERANGE; |
1189 | | - |
1190 | | - if ((mqprio->flags & TC_MQPRIO_F_SHAPER) && |
1191 | | - mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) |
1192 | | - return -EOPNOTSUPP; |
1193 | | - |
1194 | | - ret = am65_cpsw_mqprio_verify(port, mqprio); |
1195 | | - if (ret) |
1196 | | - return ret; |
1197 | | - |
1198 | | - ret = am65_cpsw_mqprio_verify_shaper(port, mqprio, &max_rate); |
1199 | | - if (ret) |
1200 | | - return ret; |
1201 | | - |
1202 | | -skip_check: |
1203 | | - ret = pm_runtime_get_sync(common->dev); |
1204 | | - if (ret < 0) { |
1205 | | - pm_runtime_put_noidle(common->dev); |
1206 | | - return ret; |
1207 | | - } |
1208 | | - |
1209 | | - if (mqprio->qopt.hw) { |
1210 | | - memcpy(&p_mqprio->mqprio_hw, mqprio, sizeof(*mqprio)); |
1211 | | - has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE); |
1212 | | - p_mqprio->enable = 1; |
1213 | | - p_mqprio->shaper_en = has_min_rate; |
1214 | | - p_mqprio->shaper_susp = !has_min_rate; |
1215 | | - p_mqprio->max_rate_total = max_rate; |
1216 | | - } else { |
1217 | | - unsigned int tc0_q = p_mqprio->tc0_q; |
1218 | | - |
1219 | | - memset(p_mqprio, 0, sizeof(*p_mqprio)); |
1220 | | - p_mqprio->mqprio_hw.qopt.num_tc = AM65_CPSW_PN_TC_NUM; |
1221 | | - p_mqprio->tc0_q = tc0_q; |
1222 | | - } |
1223 | | - |
1224 | | - if (!netif_running(ndev)) |
1225 | | - goto exit_put; |
1226 | | - |
1227 | | - am65_cpsw_qos_mqprio_init(port); |
1228 | | - |
1229 | | -exit_put: |
1230 | | - pm_runtime_put(common->dev); |
1231 | | - return 0; |
1232 | | -} |
0 commit comments