brintos

brintos / linux-shallow public Read only

0
0
Text · 49.1 KiB · 1641791 Raw
1739 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * RSS and Classifier helpers for Marvell PPv2 Network Controller4 *5 * Copyright (C) 2014 Marvell6 *7 * Marcin Wojtas <mw@semihalf.com>8 */9 10#include "mvpp2.h"11#include "mvpp2_cls.h"12#include "mvpp2_prs.h"13 14#define MVPP2_DEF_FLOW(_type, _id, _opts, _ri, _ri_mask)	\15{								\16	.flow_type = _type,					\17	.flow_id = _id,						\18	.supported_hash_opts = _opts,				\19	.prs_ri = {						\20		.ri = _ri,					\21		.ri_mask = _ri_mask				\22	}							\23}24 25static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {26	/* TCP over IPv4 flows, Not fragmented, no vlan tag */27	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,28		       MVPP22_CLS_HEK_IP4_5T,29		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |30		       MVPP2_PRS_RI_L4_TCP,31		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),32 33	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,34		       MVPP22_CLS_HEK_IP4_5T,35		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |36		       MVPP2_PRS_RI_L4_TCP,37		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),38 39	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,40		       MVPP22_CLS_HEK_IP4_5T,41		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |42		       MVPP2_PRS_RI_L4_TCP,43		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),44 45	/* TCP over IPv4 flows, Not fragmented, with vlan tag */46	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,47		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,48		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,49		       MVPP2_PRS_IP_MASK),50 51	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,52		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,53		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,54		       MVPP2_PRS_IP_MASK),55 56	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,57		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,58		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,59		       MVPP2_PRS_IP_MASK),60 61	/* TCP over IPv4 flows, fragmented, no vlan tag */62	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,63		       MVPP22_CLS_HEK_IP4_2T,64		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |65		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,66		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),67 68	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,69		       MVPP22_CLS_HEK_IP4_2T,70		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |71		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,72		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),73 74	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,75		       MVPP22_CLS_HEK_IP4_2T,76		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |77		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,78		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),79 80	/* TCP over IPv4 flows, fragmented, with vlan tag */81	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,82		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,83		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |84			   MVPP2_PRS_RI_L4_TCP,85		       MVPP2_PRS_IP_MASK),86 87	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,88		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,89		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |90			   MVPP2_PRS_RI_L4_TCP,91		       MVPP2_PRS_IP_MASK),92 93	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,94		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,95		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |96			   MVPP2_PRS_RI_L4_TCP,97		       MVPP2_PRS_IP_MASK),98 99	/* UDP over IPv4 flows, Not fragmented, no vlan tag */100	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,101		       MVPP22_CLS_HEK_IP4_5T,102		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |103		       MVPP2_PRS_RI_L4_UDP,104		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),105 106	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,107		       MVPP22_CLS_HEK_IP4_5T,108		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |109		       MVPP2_PRS_RI_L4_UDP,110		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),111 112	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,113		       MVPP22_CLS_HEK_IP4_5T,114		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |115		       MVPP2_PRS_RI_L4_UDP,116		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),117 118	/* UDP over IPv4 flows, Not fragmented, with vlan tag */119	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,120		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,121		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,122		       MVPP2_PRS_IP_MASK),123 124	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,125		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,126		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,127		       MVPP2_PRS_IP_MASK),128 129	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,130		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,131		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,132		       MVPP2_PRS_IP_MASK),133 134	/* UDP over IPv4 flows, fragmented, no vlan tag */135	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,136		       MVPP22_CLS_HEK_IP4_2T,137		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |138		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,139		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),140 141	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,142		       MVPP22_CLS_HEK_IP4_2T,143		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |144		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,145		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),146 147	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,148		       MVPP22_CLS_HEK_IP4_2T,149		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |150		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,151		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),152 153	/* UDP over IPv4 flows, fragmented, with vlan tag */154	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,155		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,156		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |157			   MVPP2_PRS_RI_L4_UDP,158		       MVPP2_PRS_IP_MASK),159 160	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,161		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,162		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |163			   MVPP2_PRS_RI_L4_UDP,164		       MVPP2_PRS_IP_MASK),165 166	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,167		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,168		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |169			   MVPP2_PRS_RI_L4_UDP,170		       MVPP2_PRS_IP_MASK),171 172	/* TCP over IPv6 flows, not fragmented, no vlan tag */173	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,174		       MVPP22_CLS_HEK_IP6_5T,175		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |176		       MVPP2_PRS_RI_L4_TCP,177		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),178 179	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,180		       MVPP22_CLS_HEK_IP6_5T,181		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |182		       MVPP2_PRS_RI_L4_TCP,183		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),184 185	/* TCP over IPv6 flows, not fragmented, with vlan tag */186	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,187		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,188		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_TCP,189		       MVPP2_PRS_IP_MASK),190 191	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,192		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,193		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_TCP,194		       MVPP2_PRS_IP_MASK),195 196	/* TCP over IPv6 flows, fragmented, no vlan tag */197	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,198		       MVPP22_CLS_HEK_IP6_2T,199		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |200		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,201		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),202 203	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,204		       MVPP22_CLS_HEK_IP6_2T,205		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |206		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,207		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),208 209	/* TCP over IPv6 flows, fragmented, with vlan tag */210	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,211		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,212		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |213		       MVPP2_PRS_RI_L4_TCP,214		       MVPP2_PRS_IP_MASK),215 216	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,217		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,218		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |219		       MVPP2_PRS_RI_L4_TCP,220		       MVPP2_PRS_IP_MASK),221 222	/* UDP over IPv6 flows, not fragmented, no vlan tag */223	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,224		       MVPP22_CLS_HEK_IP6_5T,225		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |226		       MVPP2_PRS_RI_L4_UDP,227		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),228 229	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,230		       MVPP22_CLS_HEK_IP6_5T,231		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |232		       MVPP2_PRS_RI_L4_UDP,233		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),234 235	/* UDP over IPv6 flows, not fragmented, with vlan tag */236	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,237		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,238		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_UDP,239		       MVPP2_PRS_IP_MASK),240 241	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,242		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,243		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_UDP,244		       MVPP2_PRS_IP_MASK),245 246	/* UDP over IPv6 flows, fragmented, no vlan tag */247	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,248		       MVPP22_CLS_HEK_IP6_2T,249		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |250		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,251		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),252 253	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,254		       MVPP22_CLS_HEK_IP6_2T,255		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |256		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,257		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),258 259	/* UDP over IPv6 flows, fragmented, with vlan tag */260	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,261		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,262		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |263		       MVPP2_PRS_RI_L4_UDP,264		       MVPP2_PRS_IP_MASK),265 266	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,267		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,268		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |269		       MVPP2_PRS_RI_L4_UDP,270		       MVPP2_PRS_IP_MASK),271 272	/* IPv4 flows, no vlan tag */273	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,274		       MVPP22_CLS_HEK_IP4_2T,275		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4,276		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),277	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,278		       MVPP22_CLS_HEK_IP4_2T,279		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT,280		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),281	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,282		       MVPP22_CLS_HEK_IP4_2T,283		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER,284		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),285 286	/* IPv4 flows, with vlan tag */287	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,288		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,289		       MVPP2_PRS_RI_L3_IP4,290		       MVPP2_PRS_RI_L3_PROTO_MASK),291	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,292		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,293		       MVPP2_PRS_RI_L3_IP4_OPT,294		       MVPP2_PRS_RI_L3_PROTO_MASK),295	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,296		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,297		       MVPP2_PRS_RI_L3_IP4_OTHER,298		       MVPP2_PRS_RI_L3_PROTO_MASK),299 300	/* IPv6 flows, no vlan tag */301	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,302		       MVPP22_CLS_HEK_IP6_2T,303		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,304		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),305	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,306		       MVPP22_CLS_HEK_IP6_2T,307		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,308		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),309 310	/* IPv6 flows, with vlan tag */311	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,312		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,313		       MVPP2_PRS_RI_L3_IP6,314		       MVPP2_PRS_RI_L3_PROTO_MASK),315	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,316		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,317		       MVPP2_PRS_RI_L3_IP6,318		       MVPP2_PRS_RI_L3_PROTO_MASK),319 320	/* Non IP flow, no vlan tag */321	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_UNTAG,322		       0,323		       MVPP2_PRS_RI_VLAN_NONE,324		       MVPP2_PRS_RI_VLAN_MASK),325	/* Non IP flow, with vlan tag */326	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_TAG,327		       MVPP22_CLS_HEK_OPT_VLAN,328		       0, 0),329};330 331u32 mvpp2_cls_flow_hits(struct mvpp2 *priv, int index)332{333	mvpp2_write(priv, MVPP2_CTRS_IDX, index);334 335	return mvpp2_read(priv, MVPP2_CLS_FLOW_TBL_HIT_CTR);336}337 338void mvpp2_cls_flow_read(struct mvpp2 *priv, int index,339			 struct mvpp2_cls_flow_entry *fe)340{341	fe->index = index;342	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, index);343	fe->data[0] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL0_REG);344	fe->data[1] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL1_REG);345	fe->data[2] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL2_REG);346}347 348/* Update classification flow table registers */349static void mvpp2_cls_flow_write(struct mvpp2 *priv,350				 struct mvpp2_cls_flow_entry *fe)351{352	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index);353	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]);354	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]);355	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]);356}357 358u32 mvpp2_cls_lookup_hits(struct mvpp2 *priv, int index)359{360	mvpp2_write(priv, MVPP2_CTRS_IDX, index);361 362	return mvpp2_read(priv, MVPP2_CLS_DEC_TBL_HIT_CTR);363}364 365void mvpp2_cls_lookup_read(struct mvpp2 *priv, int lkpid, int way,366			   struct mvpp2_cls_lookup_entry *le)367{368	u32 val;369 370	val = (way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | lkpid;371	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);372	le->way = way;373	le->lkpid = lkpid;374	le->data = mvpp2_read(priv, MVPP2_CLS_LKP_TBL_REG);375}376 377/* Update classification lookup table register */378static void mvpp2_cls_lookup_write(struct mvpp2 *priv,379				   struct mvpp2_cls_lookup_entry *le)380{381	u32 val;382 383	val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid;384	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);385	mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data);386}387 388/* Operations on flow entry */389static int mvpp2_cls_flow_hek_num_get(struct mvpp2_cls_flow_entry *fe)390{391	return fe->data[1] & MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;392}393 394static void mvpp2_cls_flow_hek_num_set(struct mvpp2_cls_flow_entry *fe,395				       int num_of_fields)396{397	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;398	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_N_FIELDS(num_of_fields);399}400 401static int mvpp2_cls_flow_hek_get(struct mvpp2_cls_flow_entry *fe,402				  int field_index)403{404	return (fe->data[2] >> MVPP2_CLS_FLOW_TBL2_FLD_OFFS(field_index)) &405		MVPP2_CLS_FLOW_TBL2_FLD_MASK;406}407 408static void mvpp2_cls_flow_hek_set(struct mvpp2_cls_flow_entry *fe,409				   int field_index, int field_id)410{411	fe->data[2] &= ~MVPP2_CLS_FLOW_TBL2_FLD(field_index,412						MVPP2_CLS_FLOW_TBL2_FLD_MASK);413	fe->data[2] |= MVPP2_CLS_FLOW_TBL2_FLD(field_index, field_id);414}415 416static void mvpp2_cls_flow_eng_set(struct mvpp2_cls_flow_entry *fe,417				   int engine)418{419	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_ENG(MVPP2_CLS_FLOW_TBL0_ENG_MASK);420	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_ENG(engine);421}422 423int mvpp2_cls_flow_eng_get(struct mvpp2_cls_flow_entry *fe)424{425	return (fe->data[0] >> MVPP2_CLS_FLOW_TBL0_OFFS) &426		MVPP2_CLS_FLOW_TBL0_ENG_MASK;427}428 429static void mvpp2_cls_flow_port_id_sel(struct mvpp2_cls_flow_entry *fe,430				       bool from_packet)431{432	if (from_packet)433		fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;434	else435		fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;436}437 438static void mvpp2_cls_flow_last_set(struct mvpp2_cls_flow_entry *fe,439				    bool is_last)440{441	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_LAST;442	fe->data[0] |= !!is_last;443}444 445static void mvpp2_cls_flow_pri_set(struct mvpp2_cls_flow_entry *fe, int prio)446{447	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_PRIO(MVPP2_CLS_FLOW_TBL1_PRIO_MASK);448	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_PRIO(prio);449}450 451static void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe,452				    u32 port)453{454	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port);455}456 457static void mvpp2_cls_flow_port_remove(struct mvpp2_cls_flow_entry *fe,458				       u32 port)459{460	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID(port);461}462 463static void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe,464				       u8 lu_type)465{466	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK);467	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_LU_TYPE(lu_type);468}469 470/* Initialize the parser entry for the given flow */471static void mvpp2_cls_flow_prs_init(struct mvpp2 *priv,472				    const struct mvpp2_cls_flow *flow)473{474	mvpp2_prs_add_flow(priv, flow->flow_id, flow->prs_ri.ri,475			   flow->prs_ri.ri_mask);476}477 478/* Initialize the Lookup Id table entry for the given flow */479static void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,480				    const struct mvpp2_cls_flow *flow)481{482	struct mvpp2_cls_lookup_entry le;483 484	le.way = 0;485	le.lkpid = flow->flow_id;486 487	/* The default RxQ for this port is set in the C2 lookup */488	le.data = 0;489 490	/* We point on the first lookup in the sequence for the flow, that is491	 * the C2 lookup.492	 */493	le.data |= MVPP2_CLS_LKP_FLOW_PTR(MVPP2_CLS_FLT_FIRST(flow->flow_id));494 495	/* CLS is always enabled, RSS is enabled/disabled in C2 lookup */496	le.data |= MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;497 498	mvpp2_cls_lookup_write(priv, &le);499}500 501static void mvpp2_cls_c2_write(struct mvpp2 *priv,502			       struct mvpp2_cls_c2_entry *c2)503{504	u32 val;505	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);506 507	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);508	if (c2->valid)509		val &= ~MVPP22_CLS_C2_TCAM_INV_BIT;510	else511		val |= MVPP22_CLS_C2_TCAM_INV_BIT;512	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_INV, val);513 514	mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);515 516	mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);517	mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);518	mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);519	mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);520 521	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);522	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);523	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);524	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);525	/* Writing TCAM_DATA4 flushes writes to TCAM_DATA0-4 and INV to HW */526	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);527}528 529void mvpp2_cls_c2_read(struct mvpp2 *priv, int index,530		       struct mvpp2_cls_c2_entry *c2)531{532	u32 val;533	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, index);534 535	c2->index = index;536 537	c2->tcam[0] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA0);538	c2->tcam[1] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA1);539	c2->tcam[2] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA2);540	c2->tcam[3] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA3);541	c2->tcam[4] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA4);542 543	c2->act = mvpp2_read(priv, MVPP22_CLS_C2_ACT);544 545	c2->attr[0] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR0);546	c2->attr[1] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR1);547	c2->attr[2] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR2);548	c2->attr[3] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR3);549 550	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);551	c2->valid = !(val & MVPP22_CLS_C2_TCAM_INV_BIT);552}553 554static int mvpp2_cls_ethtool_flow_to_type(int flow_type)555{556	switch (flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {557	case ETHER_FLOW:558		return MVPP22_FLOW_ETHERNET;559	case TCP_V4_FLOW:560		return MVPP22_FLOW_TCP4;561	case TCP_V6_FLOW:562		return MVPP22_FLOW_TCP6;563	case UDP_V4_FLOW:564		return MVPP22_FLOW_UDP4;565	case UDP_V6_FLOW:566		return MVPP22_FLOW_UDP6;567	case IPV4_FLOW:568		return MVPP22_FLOW_IP4;569	case IPV6_FLOW:570		return MVPP22_FLOW_IP6;571	default:572		return -EOPNOTSUPP;573	}574}575 576static int mvpp2_cls_c2_port_flow_index(struct mvpp2_port *port, int loc)577{578	return MVPP22_CLS_C2_RFS_LOC(port->id, loc);579}580 581/* Initialize the flow table entries for the given flow */582static void mvpp2_cls_flow_init(struct mvpp2 *priv,583				const struct mvpp2_cls_flow *flow)584{585	struct mvpp2_cls_flow_entry fe;586	int i, pri = 0;587 588	/* Assign default values to all entries in the flow */589	for (i = MVPP2_CLS_FLT_FIRST(flow->flow_id);590	     i <= MVPP2_CLS_FLT_LAST(flow->flow_id); i++) {591		memset(&fe, 0, sizeof(fe));592		fe.index = i;593		mvpp2_cls_flow_pri_set(&fe, pri++);594 595		if (i == MVPP2_CLS_FLT_LAST(flow->flow_id))596			mvpp2_cls_flow_last_set(&fe, 1);597 598		mvpp2_cls_flow_write(priv, &fe);599	}600 601	/* RSS config C2 lookup */602	mvpp2_cls_flow_read(priv, MVPP2_CLS_FLT_C2_RSS_ENTRY(flow->flow_id),603			    &fe);604 605	mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);606	mvpp2_cls_flow_port_id_sel(&fe, true);607	mvpp2_cls_flow_lu_type_set(&fe, MVPP22_CLS_LU_TYPE_ALL);608 609	/* Add all ports */610	for (i = 0; i < MVPP2_MAX_PORTS; i++)611		mvpp2_cls_flow_port_add(&fe, BIT(i));612 613	mvpp2_cls_flow_write(priv, &fe);614 615	/* C3Hx lookups */616	for (i = 0; i < MVPP2_MAX_PORTS; i++) {617		mvpp2_cls_flow_read(priv,618				    MVPP2_CLS_FLT_HASH_ENTRY(i, flow->flow_id),619				    &fe);620 621		/* Set a default engine. Will be overwritten when setting the622		 * real HEK parameters623		 */624		mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C3HA);625		mvpp2_cls_flow_port_id_sel(&fe, true);626		mvpp2_cls_flow_port_add(&fe, BIT(i));627 628		mvpp2_cls_flow_write(priv, &fe);629	}630}631 632/* Adds a field to the Header Extracted Key generation parameters*/633static int mvpp2_flow_add_hek_field(struct mvpp2_cls_flow_entry *fe,634				    u32 field_id)635{636	int nb_fields = mvpp2_cls_flow_hek_num_get(fe);637 638	if (nb_fields == MVPP2_FLOW_N_FIELDS)639		return -EINVAL;640 641	mvpp2_cls_flow_hek_set(fe, nb_fields, field_id);642 643	mvpp2_cls_flow_hek_num_set(fe, nb_fields + 1);644 645	return 0;646}647 648static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,649				     unsigned long hash_opts)650{651	u32 field_id;652	int i;653 654	/* Clear old fields */655	mvpp2_cls_flow_hek_num_set(fe, 0);656	fe->data[2] = 0;657 658	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {659		switch (BIT(i)) {660		case MVPP22_CLS_HEK_OPT_MAC_DA:661			field_id = MVPP22_CLS_FIELD_MAC_DA;662			break;663		case MVPP22_CLS_HEK_OPT_VLAN:664			field_id = MVPP22_CLS_FIELD_VLAN;665			break;666		case MVPP22_CLS_HEK_OPT_VLAN_PRI:667			field_id = MVPP22_CLS_FIELD_VLAN_PRI;668			break;669		case MVPP22_CLS_HEK_OPT_IP4SA:670			field_id = MVPP22_CLS_FIELD_IP4SA;671			break;672		case MVPP22_CLS_HEK_OPT_IP4DA:673			field_id = MVPP22_CLS_FIELD_IP4DA;674			break;675		case MVPP22_CLS_HEK_OPT_IP6SA:676			field_id = MVPP22_CLS_FIELD_IP6SA;677			break;678		case MVPP22_CLS_HEK_OPT_IP6DA:679			field_id = MVPP22_CLS_FIELD_IP6DA;680			break;681		case MVPP22_CLS_HEK_OPT_L4SIP:682			field_id = MVPP22_CLS_FIELD_L4SIP;683			break;684		case MVPP22_CLS_HEK_OPT_L4DIP:685			field_id = MVPP22_CLS_FIELD_L4DIP;686			break;687		default:688			return -EINVAL;689		}690		if (mvpp2_flow_add_hek_field(fe, field_id))691			return -EINVAL;692	}693 694	return 0;695}696 697/* Returns the size, in bits, of the corresponding HEK field */698static int mvpp2_cls_hek_field_size(u32 field)699{700	switch (field) {701	case MVPP22_CLS_HEK_OPT_MAC_DA:702		return 48;703	case MVPP22_CLS_HEK_OPT_VLAN:704		return 12;705	case MVPP22_CLS_HEK_OPT_VLAN_PRI:706		return 3;707	case MVPP22_CLS_HEK_OPT_IP4SA:708	case MVPP22_CLS_HEK_OPT_IP4DA:709		return 32;710	case MVPP22_CLS_HEK_OPT_IP6SA:711	case MVPP22_CLS_HEK_OPT_IP6DA:712		return 128;713	case MVPP22_CLS_HEK_OPT_L4SIP:714	case MVPP22_CLS_HEK_OPT_L4DIP:715		return 16;716	default:717		return -1;718	}719}720 721const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)722{723	if (flow >= MVPP2_N_PRS_FLOWS)724		return NULL;725 726	return &cls_flows[flow];727}728 729/* Set the hash generation options for the given traffic flow.730 * One traffic flow (in the ethtool sense) has multiple classification flows,731 * to handle specific cases such as fragmentation, or the presence of a732 * VLAN / DSA Tag.733 *734 * Each of these individual flows has different constraints, for example we735 * can't hash fragmented packets on L4 data (else we would risk having packet736 * re-ordering), so each classification flows masks the options with their737 * supported ones.738 *739 */740static int mvpp2_port_rss_hash_opts_set(struct mvpp2_port *port, int flow_type,741					u16 requested_opts)742{743	const struct mvpp2_cls_flow *flow;744	struct mvpp2_cls_flow_entry fe;745	int i, engine, flow_index;746	u16 hash_opts;747 748	for_each_cls_flow_id_with_type(i, flow_type) {749		flow = mvpp2_cls_flow_get(i);750		if (!flow)751			return -EINVAL;752 753		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);754 755		mvpp2_cls_flow_read(port->priv, flow_index, &fe);756 757		hash_opts = flow->supported_hash_opts & requested_opts;758 759		/* Use C3HB engine to access L4 infos. This adds L4 infos to the760		 * hash parameters761		 */762		if (hash_opts & MVPP22_CLS_HEK_L4_OPTS)763			engine = MVPP22_CLS_ENGINE_C3HB;764		else765			engine = MVPP22_CLS_ENGINE_C3HA;766 767		if (mvpp2_flow_set_hek_fields(&fe, hash_opts))768			return -EINVAL;769 770		mvpp2_cls_flow_eng_set(&fe, engine);771 772		mvpp2_cls_flow_write(port->priv, &fe);773	}774 775	return 0;776}777 778u16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe)779{780	u16 hash_opts = 0;781	int n_fields, i, field;782 783	n_fields = mvpp2_cls_flow_hek_num_get(fe);784 785	for (i = 0; i < n_fields; i++) {786		field = mvpp2_cls_flow_hek_get(fe, i);787 788		switch (field) {789		case MVPP22_CLS_FIELD_MAC_DA:790			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;791			break;792		case MVPP22_CLS_FIELD_VLAN:793			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;794			break;795		case MVPP22_CLS_FIELD_VLAN_PRI:796			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN_PRI;797			break;798		case MVPP22_CLS_FIELD_L3_PROTO:799			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;800			break;801		case MVPP22_CLS_FIELD_IP4SA:802			hash_opts |= MVPP22_CLS_HEK_OPT_IP4SA;803			break;804		case MVPP22_CLS_FIELD_IP4DA:805			hash_opts |= MVPP22_CLS_HEK_OPT_IP4DA;806			break;807		case MVPP22_CLS_FIELD_IP6SA:808			hash_opts |= MVPP22_CLS_HEK_OPT_IP6SA;809			break;810		case MVPP22_CLS_FIELD_IP6DA:811			hash_opts |= MVPP22_CLS_HEK_OPT_IP6DA;812			break;813		case MVPP22_CLS_FIELD_L4SIP:814			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;815			break;816		case MVPP22_CLS_FIELD_L4DIP:817			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;818			break;819		default:820			break;821		}822	}823	return hash_opts;824}825 826/* Returns the hash opts for this flow. There are several classifier flows827 * for one traffic flow, this returns an aggregation of all configurations.828 */829static u16 mvpp2_port_rss_hash_opts_get(struct mvpp2_port *port, int flow_type)830{831	const struct mvpp2_cls_flow *flow;832	struct mvpp2_cls_flow_entry fe;833	int i, flow_index;834	u16 hash_opts = 0;835 836	for_each_cls_flow_id_with_type(i, flow_type) {837		flow = mvpp2_cls_flow_get(i);838		if (!flow)839			return 0;840 841		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);842 843		mvpp2_cls_flow_read(port->priv, flow_index, &fe);844 845		hash_opts |= mvpp2_flow_get_hek_fields(&fe);846	}847 848	return hash_opts;849}850 851static void mvpp2_cls_port_init_flows(struct mvpp2 *priv)852{853	const struct mvpp2_cls_flow *flow;854	int i;855 856	for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {857		flow = mvpp2_cls_flow_get(i);858		if (!flow)859			break;860 861		mvpp2_cls_flow_prs_init(priv, flow);862		mvpp2_cls_flow_lkp_init(priv, flow);863		mvpp2_cls_flow_init(priv, flow);864	}865}866 867static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)868{869	struct mvpp2_cls_c2_entry c2;870	u8 qh, ql, pmap;871 872	memset(&c2, 0, sizeof(c2));873 874	c2.index = MVPP22_CLS_C2_RSS_ENTRY(port->id);875 876	pmap = BIT(port->id);877	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);878	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));879 880	/* Match on Lookup Type */881	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));882	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP22_CLS_LU_TYPE_ALL);883 884	/* Update RSS status after matching this entry */885	c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);886 887	/* Mark packet as "forwarded to software", needed for RSS */888	c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);889 890	/* Configure the default rx queue : Update Queue Low and Queue High, but891	 * don't lock, since the rx queue selection might be overridden by RSS892	 */893	c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD) |894		   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD);895 896	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;897	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;898 899	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |900		      MVPP22_CLS_C2_ATTR0_QLOW(ql);901 902	c2.valid = true;903 904	mvpp2_cls_c2_write(port->priv, &c2);905}906 907/* Classifier default initialization */908void mvpp2_cls_init(struct mvpp2 *priv)909{910	struct mvpp2_cls_lookup_entry le;911	struct mvpp2_cls_flow_entry fe;912	struct mvpp2_cls_c2_entry c2;913	int index;914 915	/* Enable classifier */916	mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);917 918	/* Clear classifier flow table */919	memset(&fe.data, 0, sizeof(fe.data));920	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {921		fe.index = index;922		mvpp2_cls_flow_write(priv, &fe);923	}924 925	/* Clear classifier lookup table */926	le.data = 0;927	for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) {928		le.lkpid = index;929		le.way = 0;930		mvpp2_cls_lookup_write(priv, &le);931 932		le.way = 1;933		mvpp2_cls_lookup_write(priv, &le);934	}935 936	/* Clear C2 TCAM engine table */937	memset(&c2, 0, sizeof(c2));938	c2.valid = false;939	for (index = 0; index < MVPP22_CLS_C2_N_ENTRIES; index++) {940		c2.index = index;941		mvpp2_cls_c2_write(priv, &c2);942	}943 944	/* Disable the FIFO stages in C2 engine, which are only used in BIST945	 * mode946	 */947	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_CTRL,948		    MVPP22_CLS_C2_TCAM_BYPASS_FIFO);949 950	mvpp2_cls_port_init_flows(priv);951}952 953void mvpp2_cls_port_config(struct mvpp2_port *port)954{955	struct mvpp2_cls_lookup_entry le;956	u32 val;957 958	/* Set way for the port */959	val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG);960	val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id);961	mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val);962 963	/* Pick the entry to be accessed in lookup ID decoding table964	 * according to the way and lkpid.965	 */966	le.lkpid = port->id;967	le.way = 0;968	le.data = 0;969 970	/* Set initial CPU queue for receiving packets */971	le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;972	le.data |= port->first_rxq;973 974	/* Disable classification engines */975	le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;976 977	/* Update lookup ID table entry */978	mvpp2_cls_lookup_write(port->priv, &le);979 980	mvpp2_port_c2_cls_init(port);981}982 983u32 mvpp2_cls_c2_hit_count(struct mvpp2 *priv, int c2_index)984{985	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2_index);986 987	return mvpp2_read(priv, MVPP22_CLS_C2_HIT_CTR);988}989 990static void mvpp2_rss_port_c2_enable(struct mvpp2_port *port, u32 ctx)991{992	struct mvpp2_cls_c2_entry c2;993	u8 qh, ql;994 995	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);996 997	/* The RxQ number is used to select the RSS table. It that case, we set998	 * it to be the ctx number.999	 */1000	qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;1001	ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;1002 1003	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |1004		     MVPP22_CLS_C2_ATTR0_QLOW(ql);1005 1006	c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;1007 1008	mvpp2_cls_c2_write(port->priv, &c2);1009}1010 1011static void mvpp2_rss_port_c2_disable(struct mvpp2_port *port)1012{1013	struct mvpp2_cls_c2_entry c2;1014	u8 qh, ql;1015 1016	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);1017 1018	/* Reset the default destination RxQ to the port's first rx queue. */1019	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;1020	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;1021 1022	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |1023		      MVPP22_CLS_C2_ATTR0_QLOW(ql);1024 1025	c2.attr[2] &= ~MVPP22_CLS_C2_ATTR2_RSS_EN;1026 1027	mvpp2_cls_c2_write(port->priv, &c2);1028}1029 1030static inline int mvpp22_rss_ctx(struct mvpp2_port *port, int port_rss_ctx)1031{1032	return port->rss_ctx[port_rss_ctx];1033}1034 1035int mvpp22_port_rss_enable(struct mvpp2_port *port)1036{1037	if (mvpp22_rss_ctx(port, 0) < 0)1038		return -EINVAL;1039 1040	mvpp2_rss_port_c2_enable(port, mvpp22_rss_ctx(port, 0));1041 1042	return 0;1043}1044 1045int mvpp22_port_rss_disable(struct mvpp2_port *port)1046{1047	if (mvpp22_rss_ctx(port, 0) < 0)1048		return -EINVAL;1049 1050	mvpp2_rss_port_c2_disable(port);1051 1052	return 0;1053}1054 1055static void mvpp22_port_c2_lookup_disable(struct mvpp2_port *port, int entry)1056{1057	struct mvpp2_cls_c2_entry c2;1058 1059	mvpp2_cls_c2_read(port->priv, entry, &c2);1060 1061	/* Clear the port map so that the entry doesn't match anymore */1062	c2.tcam[4] &= ~(MVPP22_CLS_C2_PORT_ID(BIT(port->id)));1063 1064	mvpp2_cls_c2_write(port->priv, &c2);1065}1066 1067/* Set CPU queue number for oversize packets */1068void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port)1069{1070	u32 val;1071 1072	mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id),1073		    port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK);1074 1075	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id),1076		    (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS));1077 1078	val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG);1079	val &= ~MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);1080	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val);1081}1082 1083static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,1084				       struct mvpp2_rfs_rule *rule)1085{1086	struct flow_action_entry *act;1087	struct mvpp2_cls_c2_entry c2;1088	u8 qh, ql, pmap;1089	int index, ctx;1090 1091	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))1092		return -EOPNOTSUPP;1093 1094	memset(&c2, 0, sizeof(c2));1095 1096	index = mvpp2_cls_c2_port_flow_index(port, rule->loc);1097	if (index < 0)1098		return -EINVAL;1099	c2.index = index;1100 1101	act = &rule->flow->action.entries[0];1102 1103	rule->c2_index = c2.index;1104 1105	c2.tcam[3] = (rule->c2_tcam & 0xffff) |1106		     ((rule->c2_tcam_mask & 0xffff) << 16);1107	c2.tcam[2] = ((rule->c2_tcam >> 16) & 0xffff) |1108		     (((rule->c2_tcam_mask >> 16) & 0xffff) << 16);1109	c2.tcam[1] = ((rule->c2_tcam >> 32) & 0xffff) |1110		     (((rule->c2_tcam_mask >> 32) & 0xffff) << 16);1111	c2.tcam[0] = ((rule->c2_tcam >> 48) & 0xffff) |1112		     (((rule->c2_tcam_mask >> 48) & 0xffff) << 16);1113 1114	pmap = BIT(port->id);1115	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);1116	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));1117 1118	/* Match on Lookup Type */1119	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));1120	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(rule->loc);1121 1122	if (act->id == FLOW_ACTION_DROP) {1123		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_RED_LOCK);1124	} else {1125		/* We want to keep the default color derived from the Header1126		 * Parser drop entries, for VLAN and MAC filtering. This will1127		 * assign a default color of Green or Red, and we want matches1128		 * with a non-drop action to keep that color.1129		 */1130		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_NO_UPD_LOCK);1131 1132		/* Update RSS status after matching this entry */1133		if (act->queue.ctx)1134			c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;1135 1136		/* Always lock the RSS_EN decision. We might have high prio1137		 * rules steering to an RXQ, and a lower one steering to RSS,1138		 * we don't want the low prio RSS rule overwriting this flag.1139		 */1140		c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);1141 1142		/* Mark packet as "forwarded to software", needed for RSS */1143		c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);1144 1145		c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD_LOCK) |1146			   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD_LOCK);1147 1148		if (act->queue.ctx) {1149			/* Get the global ctx number */1150			ctx = mvpp22_rss_ctx(port, act->queue.ctx);1151			if (ctx < 0)1152				return -EINVAL;1153 1154			qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;1155			ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;1156		} else {1157			qh = ((act->queue.index + port->first_rxq) >> 3) &1158			      MVPP22_CLS_C2_ATTR0_QHIGH_MASK;1159			ql = (act->queue.index + port->first_rxq) &1160			      MVPP22_CLS_C2_ATTR0_QLOW_MASK;1161		}1162 1163		c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |1164			      MVPP22_CLS_C2_ATTR0_QLOW(ql);1165	}1166 1167	c2.valid = true;1168 1169	mvpp2_cls_c2_write(port->priv, &c2);1170 1171	return 0;1172}1173 1174static int mvpp2_port_c2_rfs_rule_insert(struct mvpp2_port *port,1175					 struct mvpp2_rfs_rule *rule)1176{1177	return mvpp2_port_c2_tcam_rule_add(port, rule);1178}1179 1180static int mvpp2_port_cls_rfs_rule_remove(struct mvpp2_port *port,1181					  struct mvpp2_rfs_rule *rule)1182{1183	const struct mvpp2_cls_flow *flow;1184	struct mvpp2_cls_flow_entry fe;1185	int index, i;1186 1187	for_each_cls_flow_id_containing_type(i, rule->flow_type) {1188		flow = mvpp2_cls_flow_get(i);1189		if (!flow)1190			return 0;1191 1192		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);1193 1194		mvpp2_cls_flow_read(port->priv, index, &fe);1195		mvpp2_cls_flow_port_remove(&fe, BIT(port->id));1196		mvpp2_cls_flow_write(port->priv, &fe);1197	}1198 1199	if (rule->c2_index >= 0)1200		mvpp22_port_c2_lookup_disable(port, rule->c2_index);1201 1202	return 0;1203}1204 1205static int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port,1206					  struct mvpp2_rfs_rule *rule)1207{1208	const struct mvpp2_cls_flow *flow;1209	struct mvpp2 *priv = port->priv;1210	struct mvpp2_cls_flow_entry fe;1211	int index, ret, i;1212 1213	if (rule->engine != MVPP22_CLS_ENGINE_C2)1214		return -EOPNOTSUPP;1215 1216	ret = mvpp2_port_c2_rfs_rule_insert(port, rule);1217	if (ret)1218		return ret;1219 1220	for_each_cls_flow_id_containing_type(i, rule->flow_type) {1221		flow = mvpp2_cls_flow_get(i);1222		if (!flow)1223			return 0;1224 1225		if ((rule->hek_fields & flow->supported_hash_opts) != rule->hek_fields)1226			continue;1227 1228		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);1229 1230		mvpp2_cls_flow_read(priv, index, &fe);1231		mvpp2_cls_flow_eng_set(&fe, rule->engine);1232		mvpp2_cls_flow_port_id_sel(&fe, true);1233		mvpp2_flow_set_hek_fields(&fe, rule->hek_fields);1234		mvpp2_cls_flow_lu_type_set(&fe, rule->loc);1235		mvpp2_cls_flow_port_add(&fe, 0xf);1236 1237		mvpp2_cls_flow_write(priv, &fe);1238	}1239 1240	return 0;1241}1242 1243static int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule)1244{1245	struct flow_rule *flow = rule->flow;1246	int offs = 0;1247 1248	/* The order of insertion in C2 tcam must match the order in which1249	 * the fields are found in the header1250	 */1251	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_VLAN)) {1252		struct flow_match_vlan match;1253 1254		flow_rule_match_vlan(flow, &match);1255		if (match.mask->vlan_id) {1256			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN;1257 1258			rule->c2_tcam |= ((u64)match.key->vlan_id) << offs;1259			rule->c2_tcam_mask |= ((u64)match.mask->vlan_id) << offs;1260 1261			/* Don't update the offset yet */1262		}1263 1264		if (match.mask->vlan_priority) {1265			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN_PRI;1266 1267			/* VLAN pri is always at offset 13 relative to the1268			 * current offset1269			 */1270			rule->c2_tcam |= ((u64)match.key->vlan_priority) <<1271				(offs + 13);1272			rule->c2_tcam_mask |= ((u64)match.mask->vlan_priority) <<1273				(offs + 13);1274		}1275 1276		if (match.mask->vlan_dei)1277			return -EOPNOTSUPP;1278 1279		/* vlan id and prio always seem to take a full 16-bit slot in1280		 * the Header Extracted Key.1281		 */1282		offs += 16;1283	}1284 1285	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) {1286		struct flow_match_ports match;1287 1288		flow_rule_match_ports(flow, &match);1289		if (match.mask->src) {1290			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4SIP;1291 1292			rule->c2_tcam |= ((u64)ntohs(match.key->src)) << offs;1293			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->src)) << offs;1294			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP);1295		}1296 1297		if (match.mask->dst) {1298			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4DIP;1299 1300			rule->c2_tcam |= ((u64)ntohs(match.key->dst)) << offs;1301			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->dst)) << offs;1302			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP);1303		}1304	}1305 1306	if (hweight16(rule->hek_fields) > MVPP2_FLOW_N_FIELDS)1307		return -EOPNOTSUPP;1308 1309	return 0;1310}1311 1312static int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule)1313{1314	struct flow_rule *flow = rule->flow;1315	struct flow_action_entry *act;1316 1317	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))1318		return -EOPNOTSUPP;1319 1320	act = &flow->action.entries[0];1321	if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)1322		return -EOPNOTSUPP;1323 1324	/* When both an RSS context and an queue index are set, the index1325	 * is considered as an offset to be added to the indirection table1326	 * entries. We don't support this, so reject this rule.1327	 */1328	if (act->queue.ctx && act->queue.index)1329		return -EOPNOTSUPP;1330 1331	/* For now, only use the C2 engine which has a HEK size limited to 641332	 * bits for TCAM matching.1333	 */1334	rule->engine = MVPP22_CLS_ENGINE_C2;1335 1336	if (mvpp2_cls_c2_build_match(rule))1337		return -EINVAL;1338 1339	return 0;1340}1341 1342int mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port,1343			       struct ethtool_rxnfc *rxnfc)1344{1345	struct mvpp2_ethtool_fs *efs;1346 1347	if (rxnfc->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)1348		return -EINVAL;1349 1350	efs = port->rfs_rules[rxnfc->fs.location];1351	if (!efs)1352		return -ENOENT;1353 1354	memcpy(rxnfc, &efs->rxnfc, sizeof(efs->rxnfc));1355 1356	return 0;1357}1358 1359int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,1360			       struct ethtool_rxnfc *info)1361{1362	struct ethtool_rx_flow_spec_input input = {};1363	struct ethtool_rx_flow_rule *ethtool_rule;1364	struct mvpp2_ethtool_fs *efs, *old_efs;1365	int ret = 0;1366 1367	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)1368		return -EINVAL;1369 1370	efs = kzalloc(sizeof(*efs), GFP_KERNEL);1371	if (!efs)1372		return -ENOMEM;1373 1374	input.fs = &info->fs;1375 1376	/* We need to manually set the rss_ctx, since this info isn't present1377	 * in info->fs1378	 */1379	if (info->fs.flow_type & FLOW_RSS)1380		input.rss_ctx = info->rss_context;1381 1382	ethtool_rule = ethtool_rx_flow_rule_create(&input);1383	if (IS_ERR(ethtool_rule)) {1384		ret = PTR_ERR(ethtool_rule);1385		goto clean_rule;1386	}1387 1388	efs->rule.flow = ethtool_rule->rule;1389	efs->rule.flow_type = mvpp2_cls_ethtool_flow_to_type(info->fs.flow_type);1390	if (efs->rule.flow_type < 0) {1391		ret = efs->rule.flow_type;1392		goto clean_rule;1393	}1394 1395	ret = mvpp2_cls_rfs_parse_rule(&efs->rule);1396	if (ret)1397		goto clean_eth_rule;1398 1399	efs->rule.loc = info->fs.location;1400 1401	/* Replace an already existing rule */1402	if (port->rfs_rules[efs->rule.loc]) {1403		old_efs = port->rfs_rules[efs->rule.loc];1404		ret = mvpp2_port_cls_rfs_rule_remove(port, &old_efs->rule);1405		if (ret)1406			goto clean_eth_rule;1407		kfree(old_efs);1408		port->n_rfs_rules--;1409	}1410 1411	ret = mvpp2_port_flt_rfs_rule_insert(port, &efs->rule);1412	if (ret)1413		goto clean_eth_rule;1414 1415	ethtool_rx_flow_rule_destroy(ethtool_rule);1416	efs->rule.flow = NULL;1417 1418	memcpy(&efs->rxnfc, info, sizeof(*info));1419	port->rfs_rules[efs->rule.loc] = efs;1420	port->n_rfs_rules++;1421 1422	return ret;1423 1424clean_eth_rule:1425	ethtool_rx_flow_rule_destroy(ethtool_rule);1426clean_rule:1427	kfree(efs);1428	return ret;1429}1430 1431int mvpp2_ethtool_cls_rule_del(struct mvpp2_port *port,1432			       struct ethtool_rxnfc *info)1433{1434	struct mvpp2_ethtool_fs *efs;1435	int ret;1436 1437	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)1438		return -EINVAL;1439 1440	efs = port->rfs_rules[info->fs.location];1441	if (!efs)1442		return -EINVAL;1443 1444	/* Remove the rule from the engines. */1445	ret = mvpp2_port_cls_rfs_rule_remove(port, &efs->rule);1446	if (ret)1447		return ret;1448 1449	port->n_rfs_rules--;1450	port->rfs_rules[info->fs.location] = NULL;1451	kfree(efs);1452 1453	return 0;1454}1455 1456static inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq)1457{1458	int nrxqs, cpu, cpus = num_possible_cpus();1459 1460	/* Number of RXQs per CPU */1461	nrxqs = port->nrxqs / cpus;1462 1463	/* CPU that will handle this rx queue */1464	cpu = rxq / nrxqs;1465 1466	if (!cpu_online(cpu))1467		return port->first_rxq;1468 1469	/* Indirection to better distribute the paquets on the CPUs when1470	 * configuring the RSS queues.1471	 */1472	return port->first_rxq + ((rxq * nrxqs + rxq / cpus) % port->nrxqs);1473}1474 1475static void mvpp22_rss_fill_table(struct mvpp2_port *port,1476				  struct mvpp2_rss_table *table,1477				  u32 rss_ctx)1478{1479	struct mvpp2 *priv = port->priv;1480	int i;1481 1482	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {1483		u32 sel = MVPP22_RSS_INDEX_TABLE(rss_ctx) |1484			  MVPP22_RSS_INDEX_TABLE_ENTRY(i);1485		mvpp2_write(priv, MVPP22_RSS_INDEX, sel);1486 1487		mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY,1488			    mvpp22_rxfh_indir(port, table->indir[i]));1489	}1490}1491 1492static int mvpp22_rss_context_create(struct mvpp2_port *port, u32 *rss_ctx)1493{1494	struct mvpp2 *priv = port->priv;1495	u32 ctx;1496 1497	/* Find the first free RSS table */1498	for (ctx = 0; ctx < MVPP22_N_RSS_TABLES; ctx++) {1499		if (!priv->rss_tables[ctx])1500			break;1501	}1502 1503	if (ctx == MVPP22_N_RSS_TABLES)1504		return -EINVAL;1505 1506	priv->rss_tables[ctx] = kzalloc(sizeof(*priv->rss_tables[ctx]),1507					GFP_KERNEL);1508	if (!priv->rss_tables[ctx])1509		return -ENOMEM;1510 1511	*rss_ctx = ctx;1512 1513	/* Set the table width: replace the whole classifier Rx queue number1514	 * with the ones configured in RSS table entries.1515	 */1516	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(ctx));1517	mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);1518 1519	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(ctx));1520	mvpp2_write(priv, MVPP22_RXQ2RSS_TABLE, MVPP22_RSS_TABLE_POINTER(ctx));1521 1522	return 0;1523}1524 1525int mvpp22_port_rss_ctx_create(struct mvpp2_port *port, u32 port_ctx)1526{1527	u32 rss_ctx;1528	int ret;1529 1530	ret = mvpp22_rss_context_create(port, &rss_ctx);1531	if (ret)1532		return ret;1533 1534	if (WARN_ON_ONCE(port->rss_ctx[port_ctx] >= 0))1535		return -EINVAL;1536 1537	port->rss_ctx[port_ctx] = rss_ctx;1538	return 0;1539}1540 1541static struct mvpp2_rss_table *mvpp22_rss_table_get(struct mvpp2 *priv,1542						    int rss_ctx)1543{1544	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)1545		return NULL;1546 1547	return priv->rss_tables[rss_ctx];1548}1549 1550int mvpp22_port_rss_ctx_delete(struct mvpp2_port *port, u32 port_ctx)1551{1552	struct mvpp2 *priv = port->priv;1553	struct ethtool_rxnfc *rxnfc;1554	int i, rss_ctx, ret;1555 1556	rss_ctx = mvpp22_rss_ctx(port, port_ctx);1557 1558	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)1559		return -EINVAL;1560 1561	/* Invalidate any active classification rule that use this context */1562	for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {1563		if (!port->rfs_rules[i])1564			continue;1565 1566		rxnfc = &port->rfs_rules[i]->rxnfc;1567		if (!(rxnfc->fs.flow_type & FLOW_RSS) ||1568		    rxnfc->rss_context != port_ctx)1569			continue;1570 1571		ret = mvpp2_ethtool_cls_rule_del(port, rxnfc);1572		if (ret) {1573			netdev_warn(port->dev,1574				    "couldn't remove classification rule %d associated to this context",1575				    rxnfc->fs.location);1576		}1577	}1578 1579	kfree(priv->rss_tables[rss_ctx]);1580 1581	priv->rss_tables[rss_ctx] = NULL;1582	port->rss_ctx[port_ctx] = -1;1583 1584	return 0;1585}1586 1587int mvpp22_port_rss_ctx_indir_set(struct mvpp2_port *port, u32 port_ctx,1588				  const u32 *indir)1589{1590	int rss_ctx = mvpp22_rss_ctx(port, port_ctx);1591	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,1592								 rss_ctx);1593 1594	if (!rss_table)1595		return -EINVAL;1596 1597	memcpy(rss_table->indir, indir,1598	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));1599 1600	mvpp22_rss_fill_table(port, rss_table, rss_ctx);1601 1602	return 0;1603}1604 1605int mvpp22_port_rss_ctx_indir_get(struct mvpp2_port *port, u32 port_ctx,1606				  u32 *indir)1607{1608	int rss_ctx =  mvpp22_rss_ctx(port, port_ctx);1609	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,1610								 rss_ctx);1611 1612	if (!rss_table)1613		return -EINVAL;1614 1615	memcpy(indir, rss_table->indir,1616	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));1617 1618	return 0;1619}1620 1621int mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info)1622{1623	u16 hash_opts = 0;1624	u32 flow_type;1625 1626	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);1627 1628	switch (flow_type) {1629	case MVPP22_FLOW_TCP4:1630	case MVPP22_FLOW_UDP4:1631	case MVPP22_FLOW_TCP6:1632	case MVPP22_FLOW_UDP6:1633		if (info->data & RXH_L4_B_0_1)1634			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;1635		if (info->data & RXH_L4_B_2_3)1636			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;1637		fallthrough;1638	case MVPP22_FLOW_IP4:1639	case MVPP22_FLOW_IP6:1640		if (info->data & RXH_L2DA)1641			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;1642		if (info->data & RXH_VLAN)1643			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;1644		if (info->data & RXH_L3_PROTO)1645			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;1646		if (info->data & RXH_IP_SRC)1647			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4SA |1648				     MVPP22_CLS_HEK_OPT_IP6SA);1649		if (info->data & RXH_IP_DST)1650			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4DA |1651				     MVPP22_CLS_HEK_OPT_IP6DA);1652		break;1653	default: return -EOPNOTSUPP;1654	}1655 1656	return mvpp2_port_rss_hash_opts_set(port, flow_type, hash_opts);1657}1658 1659int mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info)1660{1661	unsigned long hash_opts;1662	u32 flow_type;1663	int i;1664 1665	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);1666 1667	hash_opts = mvpp2_port_rss_hash_opts_get(port, flow_type);1668	info->data = 0;1669 1670	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {1671		switch (BIT(i)) {1672		case MVPP22_CLS_HEK_OPT_MAC_DA:1673			info->data |= RXH_L2DA;1674			break;1675		case MVPP22_CLS_HEK_OPT_VLAN:1676			info->data |= RXH_VLAN;1677			break;1678		case MVPP22_CLS_HEK_OPT_L3_PROTO:1679			info->data |= RXH_L3_PROTO;1680			break;1681		case MVPP22_CLS_HEK_OPT_IP4SA:1682		case MVPP22_CLS_HEK_OPT_IP6SA:1683			info->data |= RXH_IP_SRC;1684			break;1685		case MVPP22_CLS_HEK_OPT_IP4DA:1686		case MVPP22_CLS_HEK_OPT_IP6DA:1687			info->data |= RXH_IP_DST;1688			break;1689		case MVPP22_CLS_HEK_OPT_L4SIP:1690			info->data |= RXH_L4_B_0_1;1691			break;1692		case MVPP22_CLS_HEK_OPT_L4DIP:1693			info->data |= RXH_L4_B_2_3;1694			break;1695		default:1696			return -EINVAL;1697		}1698	}1699	return 0;1700}1701 1702int mvpp22_port_rss_init(struct mvpp2_port *port)1703{1704	struct mvpp2_rss_table *table;1705	u32 context = 0;1706	int i, ret;1707 1708	for (i = 0; i < MVPP22_N_RSS_TABLES; i++)1709		port->rss_ctx[i] = -1;1710 1711	ret = mvpp22_rss_context_create(port, &context);1712	if (ret)1713		return ret;1714 1715	table = mvpp22_rss_table_get(port->priv, context);1716	if (!table)1717		return -EINVAL;1718 1719	port->rss_ctx[0] = context;1720 1721	/* Configure the first table to evenly distribute the packets across1722	 * real Rx Queues. The table entries map a hash to a port Rx Queue.1723	 */1724	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++)1725		table->indir[i] = ethtool_rxfh_indir_default(i, port->nrxqs);1726 1727	mvpp22_rss_fill_table(port, table, mvpp22_rss_ctx(port, 0));1728 1729	/* Configure default flows */1730	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP4, MVPP22_CLS_HEK_IP4_2T);1731	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP6, MVPP22_CLS_HEK_IP6_2T);1732	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP4, MVPP22_CLS_HEK_IP4_5T);1733	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP6, MVPP22_CLS_HEK_IP6_5T);1734	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP4, MVPP22_CLS_HEK_IP4_5T);1735	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP6, MVPP22_CLS_HEK_IP6_5T);1736 1737	return 0;1738}1739