diff options
-rw-r--r-- | drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c | 316 | ||||
-rw-r--r-- | drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h | 45 | ||||
-rw-r--r-- | drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 20 |
4 files changed, 410 insertions, 12 deletions
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index 67cce2736806..9d2222ab60ae 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/netdevice.h> | 14 | #include <linux/netdevice.h> |
15 | #include <linux/phy.h> | 15 | #include <linux/phy.h> |
16 | #include <linux/phylink.h> | 16 | #include <linux/phylink.h> |
17 | #include <net/flow_offload.h> | ||
17 | 18 | ||
18 | /* Fifo Registers */ | 19 | /* Fifo Registers */ |
19 | #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) | 20 | #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) |
@@ -126,6 +127,7 @@ | |||
126 | #define MVPP22_CLS_C2_TCAM_DATA4 0x1b20 | 127 | #define MVPP22_CLS_C2_TCAM_DATA4 0x1b20 |
127 | #define MVPP22_CLS_C2_LU_TYPE(lu) ((lu) & 0x3f) | 128 | #define MVPP22_CLS_C2_LU_TYPE(lu) ((lu) & 0x3f) |
128 | #define MVPP22_CLS_C2_PORT_ID(port) ((port) << 8) | 129 | #define MVPP22_CLS_C2_PORT_ID(port) ((port) << 8) |
130 | #define MVPP22_CLS_C2_PORT_MASK (0xff << 8) | ||
129 | #define MVPP22_CLS_C2_TCAM_INV 0x1b24 | 131 | #define MVPP22_CLS_C2_TCAM_INV 0x1b24 |
130 | #define MVPP22_CLS_C2_TCAM_INV_BIT BIT(31) | 132 | #define MVPP22_CLS_C2_TCAM_INV_BIT BIT(31) |
131 | #define MVPP22_CLS_C2_HIT_CTR 0x1b50 | 133 | #define MVPP22_CLS_C2_HIT_CTR 0x1b50 |
@@ -615,6 +617,10 @@ | |||
615 | #define MVPP2_BIT_IN_WORD(bit) ((bit) % 32) | 617 | #define MVPP2_BIT_IN_WORD(bit) ((bit) % 32) |
616 | 618 | ||
617 | #define MVPP2_N_PRS_FLOWS 52 | 619 | #define MVPP2_N_PRS_FLOWS 52 |
620 | #define MVPP2_N_RFS_ENTRIES_PER_FLOW 4 | ||
621 | |||
622 | /* There are 7 supported high-level flows */ | ||
623 | #define MVPP2_N_RFS_RULES (MVPP2_N_RFS_ENTRIES_PER_FLOW * 7) | ||
618 | 624 | ||
619 | /* RSS constants */ | 625 | /* RSS constants */ |
620 | #define MVPP22_RSS_TABLE_ENTRIES 32 | 626 | #define MVPP22_RSS_TABLE_ENTRIES 32 |
@@ -812,6 +818,37 @@ struct mvpp2_queue_vector { | |||
812 | struct cpumask *mask; | 818 | struct cpumask *mask; |
813 | }; | 819 | }; |
814 | 820 | ||
821 | /* Internal represention of a Flow Steering rule */ | ||
822 | struct mvpp2_rfs_rule { | ||
823 | /* Rule location inside the flow*/ | ||
824 | int loc; | ||
825 | |||
826 | /* Flow type, such as TCP_V4_FLOW, IP6_FLOW, etc. */ | ||
827 | int flow_type; | ||
828 | |||
829 | /* Index of the C2 TCAM entry handling this rule */ | ||
830 | int c2_index; | ||
831 | |||
832 | /* Header fields that needs to be extracted to match this flow */ | ||
833 | u16 hek_fields; | ||
834 | |||
835 | /* CLS engine : only c2 is supported for now. */ | ||
836 | u8 engine; | ||
837 | |||
838 | /* TCAM key and mask for C2-based steering. These fields should be | ||
839 | * encapsulated in a union should we add more engines. | ||
840 | */ | ||
841 | u64 c2_tcam; | ||
842 | u64 c2_tcam_mask; | ||
843 | |||
844 | struct flow_rule *flow; | ||
845 | }; | ||
846 | |||
847 | struct mvpp2_ethtool_fs { | ||
848 | struct mvpp2_rfs_rule rule; | ||
849 | struct ethtool_rxnfc rxnfc; | ||
850 | }; | ||
851 | |||
815 | struct mvpp2_port { | 852 | struct mvpp2_port { |
816 | u8 id; | 853 | u8 id; |
817 | 854 | ||
@@ -883,6 +920,10 @@ struct mvpp2_port { | |||
883 | 920 | ||
884 | /* RSS indirection table */ | 921 | /* RSS indirection table */ |
885 | u32 indir[MVPP22_RSS_TABLE_ENTRIES]; | 922 | u32 indir[MVPP22_RSS_TABLE_ENTRIES]; |
923 | |||
924 | /* List of steering rules active on that port */ | ||
925 | struct mvpp2_ethtool_fs *rfs_rules[MVPP2_N_RFS_RULES]; | ||
926 | int n_rfs_rules; | ||
886 | }; | 927 | }; |
887 | 928 | ||
888 | /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the | 929 | /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the |
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c index 2bbd4c294fc9..f4dd59c00d80 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c | |||
@@ -448,6 +448,12 @@ static void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe, | |||
448 | fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port); | 448 | fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port); |
449 | } | 449 | } |
450 | 450 | ||
451 | static void mvpp2_cls_flow_port_remove(struct mvpp2_cls_flow_entry *fe, | ||
452 | u32 port) | ||
453 | { | ||
454 | fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID(port); | ||
455 | } | ||
456 | |||
451 | static void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe, | 457 | static void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe, |
452 | u8 lu_type) | 458 | u8 lu_type) |
453 | { | 459 | { |
@@ -559,6 +565,11 @@ static int mvpp2_cls_ethtool_flow_to_type(int flow_type) | |||
559 | } | 565 | } |
560 | } | 566 | } |
561 | 567 | ||
568 | static int mvpp2_cls_c2_port_flow_index(struct mvpp2_port *port, int loc) | ||
569 | { | ||
570 | return MVPP22_CLS_C2_RFS_LOC(port->id, loc); | ||
571 | } | ||
572 | |||
562 | /* Initialize the flow table entries for the given flow */ | 573 | /* Initialize the flow table entries for the given flow */ |
563 | static void mvpp2_cls_flow_init(struct mvpp2 *priv, | 574 | static void mvpp2_cls_flow_init(struct mvpp2 *priv, |
564 | const struct mvpp2_cls_flow *flow) | 575 | const struct mvpp2_cls_flow *flow) |
@@ -672,6 +683,26 @@ static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe, | |||
672 | return 0; | 683 | return 0; |
673 | } | 684 | } |
674 | 685 | ||
686 | /* Returns the size, in bits, of the corresponding HEK field */ | ||
687 | static int mvpp2_cls_hek_field_size(u32 field) | ||
688 | { | ||
689 | switch (field) { | ||
690 | case MVPP22_CLS_HEK_OPT_MAC_DA: | ||
691 | return 48; | ||
692 | case MVPP22_CLS_HEK_OPT_IP4SA: | ||
693 | case MVPP22_CLS_HEK_OPT_IP4DA: | ||
694 | return 32; | ||
695 | case MVPP22_CLS_HEK_OPT_IP6SA: | ||
696 | case MVPP22_CLS_HEK_OPT_IP6DA: | ||
697 | return 128; | ||
698 | case MVPP22_CLS_HEK_OPT_L4SIP: | ||
699 | case MVPP22_CLS_HEK_OPT_L4DIP: | ||
700 | return 16; | ||
701 | default: | ||
702 | return -1; | ||
703 | } | ||
704 | } | ||
705 | |||
675 | const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow) | 706 | const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow) |
676 | { | 707 | { |
677 | if (flow >= MVPP2_N_PRS_FLOWS) | 708 | if (flow >= MVPP2_N_PRS_FLOWS) |
@@ -964,6 +995,18 @@ void mvpp22_port_rss_disable(struct mvpp2_port *port) | |||
964 | mvpp2_rss_port_c2_disable(port); | 995 | mvpp2_rss_port_c2_disable(port); |
965 | } | 996 | } |
966 | 997 | ||
998 | static void mvpp22_port_c2_lookup_disable(struct mvpp2_port *port, int entry) | ||
999 | { | ||
1000 | struct mvpp2_cls_c2_entry c2; | ||
1001 | |||
1002 | mvpp2_cls_c2_read(port->priv, entry, &c2); | ||
1003 | |||
1004 | /* Clear the port map so that the entry doesn't match anymore */ | ||
1005 | c2.tcam[4] &= ~(MVPP22_CLS_C2_PORT_ID(BIT(port->id))); | ||
1006 | |||
1007 | mvpp2_cls_c2_write(port->priv, &c2); | ||
1008 | } | ||
1009 | |||
967 | /* Set CPU queue number for oversize packets */ | 1010 | /* Set CPU queue number for oversize packets */ |
968 | void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) | 1011 | void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) |
969 | { | 1012 | { |
@@ -980,6 +1023,279 @@ void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) | |||
980 | mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val); | 1023 | mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val); |
981 | } | 1024 | } |
982 | 1025 | ||
1026 | static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port, | ||
1027 | struct mvpp2_rfs_rule *rule) | ||
1028 | { | ||
1029 | struct flow_action_entry *act; | ||
1030 | struct mvpp2_cls_c2_entry c2; | ||
1031 | u8 qh, ql, pmap; | ||
1032 | |||
1033 | memset(&c2, 0, sizeof(c2)); | ||
1034 | |||
1035 | c2.index = mvpp2_cls_c2_port_flow_index(port, rule->loc); | ||
1036 | if (c2.index < 0) | ||
1037 | return -EINVAL; | ||
1038 | |||
1039 | act = &rule->flow->action.entries[0]; | ||
1040 | |||
1041 | rule->c2_index = c2.index; | ||
1042 | |||
1043 | c2.tcam[0] = (rule->c2_tcam & 0xffff) | | ||
1044 | ((rule->c2_tcam_mask & 0xffff) << 16); | ||
1045 | c2.tcam[1] = ((rule->c2_tcam >> 16) & 0xffff) | | ||
1046 | (((rule->c2_tcam_mask >> 16) & 0xffff) << 16); | ||
1047 | c2.tcam[2] = ((rule->c2_tcam >> 32) & 0xffff) | | ||
1048 | (((rule->c2_tcam_mask >> 32) & 0xffff) << 16); | ||
1049 | c2.tcam[3] = ((rule->c2_tcam >> 48) & 0xffff) | | ||
1050 | (((rule->c2_tcam_mask >> 48) & 0xffff) << 16); | ||
1051 | |||
1052 | pmap = BIT(port->id); | ||
1053 | c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap); | ||
1054 | c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap)); | ||
1055 | |||
1056 | /* Match on Lookup Type */ | ||
1057 | c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK)); | ||
1058 | c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(rule->loc); | ||
1059 | |||
1060 | /* Mark packet as "forwarded to software", needed for RSS */ | ||
1061 | c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK); | ||
1062 | |||
1063 | c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD_LOCK) | | ||
1064 | MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD_LOCK); | ||
1065 | |||
1066 | qh = ((act->queue.index + port->first_rxq) >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK; | ||
1067 | ql = (act->queue.index + port->first_rxq) & MVPP22_CLS_C2_ATTR0_QLOW_MASK; | ||
1068 | |||
1069 | c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) | | ||
1070 | MVPP22_CLS_C2_ATTR0_QLOW(ql); | ||
1071 | |||
1072 | c2.valid = true; | ||
1073 | |||
1074 | mvpp2_cls_c2_write(port->priv, &c2); | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int mvpp2_port_c2_rfs_rule_insert(struct mvpp2_port *port, | ||
1080 | struct mvpp2_rfs_rule *rule) | ||
1081 | { | ||
1082 | return mvpp2_port_c2_tcam_rule_add(port, rule); | ||
1083 | } | ||
1084 | |||
1085 | static int mvpp2_port_cls_rfs_rule_remove(struct mvpp2_port *port, | ||
1086 | struct mvpp2_rfs_rule *rule) | ||
1087 | { | ||
1088 | const struct mvpp2_cls_flow *flow; | ||
1089 | struct mvpp2_cls_flow_entry fe; | ||
1090 | int index, i; | ||
1091 | |||
1092 | for_each_cls_flow_id_containing_type(i, rule->flow_type) { | ||
1093 | flow = mvpp2_cls_flow_get(i); | ||
1094 | if (!flow) | ||
1095 | return 0; | ||
1096 | |||
1097 | index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc); | ||
1098 | |||
1099 | mvpp2_cls_flow_read(port->priv, index, &fe); | ||
1100 | mvpp2_cls_flow_port_remove(&fe, BIT(port->id)); | ||
1101 | mvpp2_cls_flow_write(port->priv, &fe); | ||
1102 | } | ||
1103 | |||
1104 | if (rule->c2_index >= 0) | ||
1105 | mvpp22_port_c2_lookup_disable(port, rule->c2_index); | ||
1106 | |||
1107 | return 0; | ||
1108 | } | ||
1109 | |||
1110 | static int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port, | ||
1111 | struct mvpp2_rfs_rule *rule) | ||
1112 | { | ||
1113 | const struct mvpp2_cls_flow *flow; | ||
1114 | struct mvpp2 *priv = port->priv; | ||
1115 | struct mvpp2_cls_flow_entry fe; | ||
1116 | int index, ret, i; | ||
1117 | |||
1118 | if (rule->engine != MVPP22_CLS_ENGINE_C2) | ||
1119 | return -EOPNOTSUPP; | ||
1120 | |||
1121 | ret = mvpp2_port_c2_rfs_rule_insert(port, rule); | ||
1122 | if (ret) | ||
1123 | return ret; | ||
1124 | |||
1125 | for_each_cls_flow_id_containing_type(i, rule->flow_type) { | ||
1126 | flow = mvpp2_cls_flow_get(i); | ||
1127 | if (!flow) | ||
1128 | return 0; | ||
1129 | |||
1130 | index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc); | ||
1131 | |||
1132 | mvpp2_cls_flow_read(priv, index, &fe); | ||
1133 | mvpp2_cls_flow_eng_set(&fe, rule->engine); | ||
1134 | mvpp2_cls_flow_port_id_sel(&fe, true); | ||
1135 | mvpp2_flow_set_hek_fields(&fe, rule->hek_fields); | ||
1136 | mvpp2_cls_flow_lu_type_set(&fe, rule->loc); | ||
1137 | mvpp2_cls_flow_port_add(&fe, 0xf); | ||
1138 | |||
1139 | mvpp2_cls_flow_write(priv, &fe); | ||
1140 | } | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | static int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule) | ||
1146 | { | ||
1147 | struct flow_rule *flow = rule->flow; | ||
1148 | struct flow_action_entry *act; | ||
1149 | int offs = 64; | ||
1150 | |||
1151 | act = &flow->action.entries[0]; | ||
1152 | |||
1153 | if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) { | ||
1154 | struct flow_match_ports match; | ||
1155 | |||
1156 | flow_rule_match_ports(flow, &match); | ||
1157 | if (match.mask->src) { | ||
1158 | rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4SIP; | ||
1159 | offs -= mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP); | ||
1160 | |||
1161 | rule->c2_tcam |= ((u64)ntohs(match.key->src)) << offs; | ||
1162 | rule->c2_tcam_mask |= ((u64)ntohs(match.mask->src)) << offs; | ||
1163 | } | ||
1164 | |||
1165 | if (match.mask->dst) { | ||
1166 | rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4DIP; | ||
1167 | offs -= mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP); | ||
1168 | |||
1169 | rule->c2_tcam |= ((u64)ntohs(match.key->dst)) << offs; | ||
1170 | rule->c2_tcam_mask |= ((u64)ntohs(match.mask->dst)) << offs; | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | if (hweight16(rule->hek_fields) > MVPP2_FLOW_N_FIELDS) | ||
1175 | return -EOPNOTSUPP; | ||
1176 | |||
1177 | return 0; | ||
1178 | } | ||
1179 | |||
1180 | static int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule) | ||
1181 | { | ||
1182 | struct flow_rule *flow = rule->flow; | ||
1183 | struct flow_action_entry *act; | ||
1184 | |||
1185 | act = &flow->action.entries[0]; | ||
1186 | if (act->id != FLOW_ACTION_QUEUE) | ||
1187 | return -EOPNOTSUPP; | ||
1188 | |||
1189 | /* For now, only use the C2 engine which has a HEK size limited to 64 | ||
1190 | * bits for TCAM matching. | ||
1191 | */ | ||
1192 | rule->engine = MVPP22_CLS_ENGINE_C2; | ||
1193 | |||
1194 | if (mvpp2_cls_c2_build_match(rule)) | ||
1195 | return -EINVAL; | ||
1196 | |||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | int mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port, | ||
1201 | struct ethtool_rxnfc *rxnfc) | ||
1202 | { | ||
1203 | struct mvpp2_ethtool_fs *efs; | ||
1204 | |||
1205 | if (rxnfc->fs.location >= MVPP2_N_RFS_RULES) | ||
1206 | return -EINVAL; | ||
1207 | |||
1208 | efs = port->rfs_rules[rxnfc->fs.location]; | ||
1209 | if (!efs) | ||
1210 | return -ENOENT; | ||
1211 | |||
1212 | memcpy(rxnfc, &efs->rxnfc, sizeof(efs->rxnfc)); | ||
1213 | |||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port, | ||
1218 | struct ethtool_rxnfc *info) | ||
1219 | { | ||
1220 | struct ethtool_rx_flow_spec_input input = {}; | ||
1221 | struct ethtool_rx_flow_rule *ethtool_rule; | ||
1222 | struct mvpp2_ethtool_fs *efs, *old_efs; | ||
1223 | int ret = 0; | ||
1224 | |||
1225 | if (info->fs.location >= 4 || | ||
1226 | info->fs.location < 0) | ||
1227 | return -EINVAL; | ||
1228 | |||
1229 | efs = kzalloc(sizeof(*efs), GFP_KERNEL); | ||
1230 | if (!efs) | ||
1231 | return -ENOMEM; | ||
1232 | |||
1233 | input.fs = &info->fs; | ||
1234 | |||
1235 | ethtool_rule = ethtool_rx_flow_rule_create(&input); | ||
1236 | if (IS_ERR(ethtool_rule)) { | ||
1237 | ret = PTR_ERR(ethtool_rule); | ||
1238 | goto clean_rule; | ||
1239 | } | ||
1240 | |||
1241 | efs->rule.flow = ethtool_rule->rule; | ||
1242 | efs->rule.flow_type = mvpp2_cls_ethtool_flow_to_type(info->fs.flow_type); | ||
1243 | |||
1244 | ret = mvpp2_cls_rfs_parse_rule(&efs->rule); | ||
1245 | if (ret) | ||
1246 | goto clean_eth_rule; | ||
1247 | |||
1248 | efs->rule.loc = info->fs.location; | ||
1249 | |||
1250 | /* Replace an already existing rule */ | ||
1251 | if (port->rfs_rules[efs->rule.loc]) { | ||
1252 | old_efs = port->rfs_rules[efs->rule.loc]; | ||
1253 | ret = mvpp2_port_cls_rfs_rule_remove(port, &old_efs->rule); | ||
1254 | if (ret) | ||
1255 | goto clean_eth_rule; | ||
1256 | kfree(old_efs); | ||
1257 | port->n_rfs_rules--; | ||
1258 | } | ||
1259 | |||
1260 | ret = mvpp2_port_flt_rfs_rule_insert(port, &efs->rule); | ||
1261 | if (ret) | ||
1262 | goto clean_eth_rule; | ||
1263 | |||
1264 | memcpy(&efs->rxnfc, info, sizeof(*info)); | ||
1265 | port->rfs_rules[efs->rule.loc] = efs; | ||
1266 | port->n_rfs_rules++; | ||
1267 | |||
1268 | return ret; | ||
1269 | |||
1270 | clean_eth_rule: | ||
1271 | ethtool_rx_flow_rule_destroy(ethtool_rule); | ||
1272 | clean_rule: | ||
1273 | kfree(efs); | ||
1274 | return ret; | ||
1275 | } | ||
1276 | |||
1277 | int mvpp2_ethtool_cls_rule_del(struct mvpp2_port *port, | ||
1278 | struct ethtool_rxnfc *info) | ||
1279 | { | ||
1280 | struct mvpp2_ethtool_fs *efs; | ||
1281 | int ret; | ||
1282 | |||
1283 | efs = port->rfs_rules[info->fs.location]; | ||
1284 | if (!efs) | ||
1285 | return -EINVAL; | ||
1286 | |||
1287 | /* Remove the rule from the engines. */ | ||
1288 | ret = mvpp2_port_cls_rfs_rule_remove(port, &efs->rule); | ||
1289 | if (ret) | ||
1290 | return ret; | ||
1291 | |||
1292 | port->n_rfs_rules--; | ||
1293 | port->rfs_rules[info->fs.location] = NULL; | ||
1294 | kfree(efs); | ||
1295 | |||
1296 | return 0; | ||
1297 | } | ||
1298 | |||
983 | static inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq) | 1299 | static inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq) |
984 | { | 1300 | { |
985 | int nrxqs, cpu, cpus = num_possible_cpus(); | 1301 | int nrxqs, cpu, cpus = num_possible_cpus(); |
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h index 284a16225370..431563a13524 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h | |||
@@ -125,11 +125,18 @@ struct mvpp2_cls_c2_entry { | |||
125 | #define MVPP22_CLS_C2_N_ENTRIES 256 | 125 | #define MVPP22_CLS_C2_N_ENTRIES 256 |
126 | 126 | ||
127 | /* Number of per-port dedicated entries in the C2 TCAM */ | 127 | /* Number of per-port dedicated entries in the C2 TCAM */ |
128 | #define MVPP22_CLS_C2_PORT_RANGE 8 | 128 | #define MVPP22_CLS_C2_PORT_N_FLOWS MVPP2_N_RFS_ENTRIES_PER_FLOW |
129 | 129 | ||
130 | #define MVPP22_CLS_C2_PORT_FIRST(p) (MVPP22_CLS_C2_N_ENTRIES - \ | 130 | /* Each port has oen range per flow type + one entry controling the global RSS |
131 | ((p) * MVPP22_CLS_C2_PORT_RANGE)) | 131 | * setting and the default rx queue |
132 | #define MVPP22_CLS_C2_RSS_ENTRY(p) (MVPP22_CLS_C2_PORT_FIRST(p) - 1) | 132 | */ |
133 | #define MVPP22_CLS_C2_PORT_RANGE (MVPP22_CLS_C2_PORT_N_FLOWS + 1) | ||
134 | #define MVPP22_CLS_C2_PORT_FIRST(p) ((p) * MVPP22_CLS_C2_PORT_RANGE) | ||
135 | #define MVPP22_CLS_C2_RSS_ENTRY(p) (MVPP22_CLS_C2_PORT_FIRST((p) + 1) - 1) | ||
136 | |||
137 | #define MVPP22_CLS_C2_PORT_FLOW_FIRST(p) (MVPP22_CLS_C2_PORT_FIRST(p)) | ||
138 | |||
139 | #define MVPP22_CLS_C2_RFS_LOC(p, loc) (MVPP22_CLS_C2_PORT_FLOW_FIRST(p) + (loc)) | ||
133 | 140 | ||
134 | /* Packet flow ID */ | 141 | /* Packet flow ID */ |
135 | enum mvpp2_prs_flow { | 142 | enum mvpp2_prs_flow { |
@@ -159,10 +166,6 @@ enum mvpp2_prs_flow { | |||
159 | MVPP2_FL_LAST, | 166 | MVPP2_FL_LAST, |
160 | }; | 167 | }; |
161 | 168 | ||
162 | enum mvpp2_cls_lu_type { | ||
163 | MVPP2_CLS_LU_ALL = 0, | ||
164 | }; | ||
165 | |||
166 | /* LU Type defined for all engines, and specified in the flow table */ | 169 | /* LU Type defined for all engines, and specified in the flow table */ |
167 | #define MVPP2_CLS_LU_TYPE_MASK 0x3f | 170 | #define MVPP2_CLS_LU_TYPE_MASK 0x3f |
168 | 171 | ||
@@ -182,11 +185,16 @@ struct mvpp2_cls_flow { | |||
182 | struct mvpp2_prs_result_info prs_ri; | 185 | struct mvpp2_prs_result_info prs_ri; |
183 | }; | 186 | }; |
184 | 187 | ||
185 | #define MVPP2_CLS_FLT_ENTRIES_PER_FLOW (MVPP2_MAX_PORTS + 1) | 188 | #define MVPP2_CLS_FLT_ENTRIES_PER_FLOW (MVPP2_MAX_PORTS + 1 + 16) |
186 | #define MVPP2_CLS_FLT_FIRST(id) (((id) - MVPP2_FL_START) * \ | 189 | #define MVPP2_CLS_FLT_FIRST(id) (((id) - MVPP2_FL_START) * \ |
187 | MVPP2_CLS_FLT_ENTRIES_PER_FLOW) | 190 | MVPP2_CLS_FLT_ENTRIES_PER_FLOW) |
188 | #define MVPP2_CLS_FLT_C2_RSS_ENTRY(id) (MVPP2_CLS_FLT_FIRST(id)) | 191 | |
189 | #define MVPP2_CLS_FLT_HASH_ENTRY(port, id) (MVPP2_CLS_FLT_C2_RSS_ENTRY(id) + (port) + 1) | 192 | #define MVPP2_CLS_FLT_C2_RFS(port, id, rfs_n) (MVPP2_CLS_FLT_FIRST(id) + \ |
193 | ((port) * MVPP2_MAX_PORTS) + \ | ||
194 | (rfs_n)) | ||
195 | |||
196 | #define MVPP2_CLS_FLT_C2_RSS_ENTRY(id) (MVPP2_CLS_FLT_C2_RFS(MVPP2_MAX_PORTS, id, 0)) | ||
197 | #define MVPP2_CLS_FLT_HASH_ENTRY(port, id) (MVPP2_CLS_FLT_C2_RSS_ENTRY(id) + 1 + (port)) | ||
190 | #define MVPP2_CLS_FLT_LAST(id) (MVPP2_CLS_FLT_FIRST(id) + \ | 198 | #define MVPP2_CLS_FLT_LAST(id) (MVPP2_CLS_FLT_FIRST(id) + \ |
191 | MVPP2_CLS_FLT_ENTRIES_PER_FLOW - 1) | 199 | MVPP2_CLS_FLT_ENTRIES_PER_FLOW - 1) |
192 | 200 | ||
@@ -213,6 +221,12 @@ struct mvpp2_cls_flow { | |||
213 | continue; \ | 221 | continue; \ |
214 | else | 222 | else |
215 | 223 | ||
224 | #define for_each_cls_flow_id_containing_type(i, type) \ | ||
225 | for_each_cls_flow_id((i)) \ | ||
226 | if ((cls_flows[(i)].flow_type & (type)) != (type)) \ | ||
227 | continue; \ | ||
228 | else | ||
229 | |||
216 | struct mvpp2_cls_flow_entry { | 230 | struct mvpp2_cls_flow_entry { |
217 | u32 index; | 231 | u32 index; |
218 | u32 data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS]; | 232 | u32 data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS]; |
@@ -260,4 +274,13 @@ u32 mvpp2_cls_c2_hit_count(struct mvpp2 *priv, int c2_index); | |||
260 | void mvpp2_cls_c2_read(struct mvpp2 *priv, int index, | 274 | void mvpp2_cls_c2_read(struct mvpp2 *priv, int index, |
261 | struct mvpp2_cls_c2_entry *c2); | 275 | struct mvpp2_cls_c2_entry *c2); |
262 | 276 | ||
277 | int mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port, | ||
278 | struct ethtool_rxnfc *rxnfc); | ||
279 | |||
280 | int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port, | ||
281 | struct ethtool_rxnfc *info); | ||
282 | |||
283 | int mvpp2_ethtool_cls_rule_del(struct mvpp2_port *port, | ||
284 | struct ethtool_rxnfc *info); | ||
285 | |||
263 | #endif | 286 | #endif |
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index f128ea22b339..56d43d9b43ef 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | |||
@@ -3937,7 +3937,7 @@ static int mvpp2_ethtool_get_rxnfc(struct net_device *dev, | |||
3937 | struct ethtool_rxnfc *info, u32 *rules) | 3937 | struct ethtool_rxnfc *info, u32 *rules) |
3938 | { | 3938 | { |
3939 | struct mvpp2_port *port = netdev_priv(dev); | 3939 | struct mvpp2_port *port = netdev_priv(dev); |
3940 | int ret = 0; | 3940 | int ret = 0, i, loc = 0; |
3941 | 3941 | ||
3942 | if (!mvpp22_rss_is_supported()) | 3942 | if (!mvpp22_rss_is_supported()) |
3943 | return -EOPNOTSUPP; | 3943 | return -EOPNOTSUPP; |
@@ -3949,6 +3949,18 @@ static int mvpp2_ethtool_get_rxnfc(struct net_device *dev, | |||
3949 | case ETHTOOL_GRXRINGS: | 3949 | case ETHTOOL_GRXRINGS: |
3950 | info->data = port->nrxqs; | 3950 | info->data = port->nrxqs; |
3951 | break; | 3951 | break; |
3952 | case ETHTOOL_GRXCLSRLCNT: | ||
3953 | info->rule_cnt = port->n_rfs_rules; | ||
3954 | break; | ||
3955 | case ETHTOOL_GRXCLSRULE: | ||
3956 | ret = mvpp2_ethtool_cls_rule_get(port, info); | ||
3957 | break; | ||
3958 | case ETHTOOL_GRXCLSRLALL: | ||
3959 | for (i = 0; i < MVPP2_N_RFS_RULES; i++) { | ||
3960 | if (port->rfs_rules[i]) | ||
3961 | rules[loc++] = i; | ||
3962 | } | ||
3963 | break; | ||
3952 | default: | 3964 | default: |
3953 | return -ENOTSUPP; | 3965 | return -ENOTSUPP; |
3954 | } | 3966 | } |
@@ -3969,6 +3981,12 @@ static int mvpp2_ethtool_set_rxnfc(struct net_device *dev, | |||
3969 | case ETHTOOL_SRXFH: | 3981 | case ETHTOOL_SRXFH: |
3970 | ret = mvpp2_ethtool_rxfh_set(port, info); | 3982 | ret = mvpp2_ethtool_rxfh_set(port, info); |
3971 | break; | 3983 | break; |
3984 | case ETHTOOL_SRXCLSRLINS: | ||
3985 | ret = mvpp2_ethtool_cls_rule_ins(port, info); | ||
3986 | break; | ||
3987 | case ETHTOOL_SRXCLSRLDEL: | ||
3988 | ret = mvpp2_ethtool_cls_rule_del(port, info); | ||
3989 | break; | ||
3972 | default: | 3990 | default: |
3973 | return -EOPNOTSUPP; | 3991 | return -EOPNOTSUPP; |
3974 | } | 3992 | } |