diff options
Diffstat (limited to 'drivers')
| -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 | } |
