aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h41
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c316
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h45
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c20
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 */
822struct 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
847struct mvpp2_ethtool_fs {
848 struct mvpp2_rfs_rule rule;
849 struct ethtool_rxnfc rxnfc;
850};
851
815struct mvpp2_port { 852struct 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
451static 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
451static void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe, 457static 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
568static 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 */
563static void mvpp2_cls_flow_init(struct mvpp2 *priv, 574static 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 */
687static 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
675const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow) 706const 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
998static 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 */
968void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) 1011void 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
1026static 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
1079static 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
1085static 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
1110static 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
1145static 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
1180static 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
1200int 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
1217int 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
1270clean_eth_rule:
1271 ethtool_rx_flow_rule_destroy(ethtool_rule);
1272clean_rule:
1273 kfree(efs);
1274 return ret;
1275}
1276
1277int 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
983static inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq) 1299static 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 */
135enum mvpp2_prs_flow { 142enum mvpp2_prs_flow {
@@ -159,10 +166,6 @@ enum mvpp2_prs_flow {
159 MVPP2_FL_LAST, 166 MVPP2_FL_LAST,
160}; 167};
161 168
162enum 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
216struct mvpp2_cls_flow_entry { 230struct 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);
260void mvpp2_cls_c2_read(struct mvpp2 *priv, int index, 274void 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
277int mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port,
278 struct ethtool_rxnfc *rxnfc);
279
280int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
281 struct ethtool_rxnfc *info);
282
283int 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 }