18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * RSS and Classifier helpers for Marvell PPv2 Network Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Marcin Wojtas <mw@semihalf.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "mvpp2.h"
118c2ecf20Sopenharmony_ci#include "mvpp2_cls.h"
128c2ecf20Sopenharmony_ci#include "mvpp2_prs.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define MVPP2_DEF_FLOW(_type, _id, _opts, _ri, _ri_mask)	\
158c2ecf20Sopenharmony_ci{								\
168c2ecf20Sopenharmony_ci	.flow_type = _type,					\
178c2ecf20Sopenharmony_ci	.flow_id = _id,						\
188c2ecf20Sopenharmony_ci	.supported_hash_opts = _opts,				\
198c2ecf20Sopenharmony_ci	.prs_ri = {						\
208c2ecf20Sopenharmony_ci		.ri = _ri,					\
218c2ecf20Sopenharmony_ci		.ri_mask = _ri_mask				\
228c2ecf20Sopenharmony_ci	}							\
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
268c2ecf20Sopenharmony_ci	/* TCP over IPv4 flows, Not fragmented, no vlan tag */
278c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
288c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
298c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
308c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
318c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
348c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
358c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
368c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
378c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
408c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
418c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
428c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
438c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* TCP over IPv4 flows, Not fragmented, with vlan tag */
468c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
478c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
488c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
498c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
528c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
538c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
548c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
578c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
588c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
598c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* TCP over IPv4 flows, fragmented, no vlan tag */
628c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
638c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
648c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
658c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
668c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
698c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
708c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
718c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
728c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
758c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
768c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
778c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
788c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* TCP over IPv4 flows, fragmented, with vlan tag */
818c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
828c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
838c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
848c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
878c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
888c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
898c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
928c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
938c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
948c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* UDP over IPv4 flows, Not fragmented, no vlan tag */
978c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
988c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
998c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
1008c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1018c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
1048c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
1058c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
1068c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1078c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
1108c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
1118c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
1128c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1138c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* UDP over IPv4 flows, Not fragmented, with vlan tag */
1168c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
1178c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
1188c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
1198c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
1228c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
1238c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
1248c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
1278c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
1288c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
1298c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* UDP over IPv4 flows, fragmented, no vlan tag */
1328c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
1338c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
1348c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
1358c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1368c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
1398c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
1408c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
1418c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1428c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
1458c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
1468c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
1478c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
1488c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* UDP over IPv4 flows, fragmented, with vlan tag */
1518c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
1528c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
1538c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
1548c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
1578c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
1588c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
1598c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
1628c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
1638c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
1648c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* TCP over IPv6 flows, not fragmented, no vlan tag */
1678c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,
1688c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
1698c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
1708c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
1718c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,
1748c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
1758c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
1768c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
1778c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* TCP over IPv6 flows, not fragmented, with vlan tag */
1808c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
1818c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
1828c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_TCP,
1838c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
1868c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
1878c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_TCP,
1888c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/* TCP over IPv6 flows, fragmented, no vlan tag */
1918c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,
1928c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
1938c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
1948c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
1958c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,
1988c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
1998c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
2008c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
2018c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* TCP over IPv6 flows, fragmented, with vlan tag */
2048c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
2058c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
2068c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
2078c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
2088c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
2118c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
2128c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
2138c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
2148c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* UDP over IPv6 flows, not fragmented, no vlan tag */
2178c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,
2188c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
2198c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
2208c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
2218c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,
2248c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
2258c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
2268c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
2278c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* UDP over IPv6 flows, not fragmented, with vlan tag */
2308c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
2318c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
2328c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_UDP,
2338c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
2368c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
2378c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_UDP,
2388c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* UDP over IPv6 flows, fragmented, no vlan tag */
2418c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,
2428c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
2438c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
2448c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
2458c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,
2488c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
2498c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
2508c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
2518c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* UDP over IPv6 flows, fragmented, with vlan tag */
2548c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
2558c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
2568c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
2578c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
2588c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
2618c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
2628c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
2638c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
2648c2ecf20Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* IPv4 flows, no vlan tag */
2678c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
2688c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
2698c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4,
2708c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
2718c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
2728c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
2738c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT,
2748c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
2758c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
2768c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
2778c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER,
2788c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* IPv4 flows, with vlan tag */
2818c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
2828c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
2838c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4,
2848c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
2858c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
2868c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
2878c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT,
2888c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
2898c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
2908c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
2918c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER,
2928c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* IPv6 flows, no vlan tag */
2958c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,
2968c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
2978c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,
2988c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
2998c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,
3008c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
3018c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,
3028c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* IPv6 flows, with vlan tag */
3058c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
3068c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
3078c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6,
3088c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
3098c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
3108c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
3118c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6,
3128c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Non IP flow, no vlan tag */
3158c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_UNTAG,
3168c2ecf20Sopenharmony_ci		       0,
3178c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE,
3188c2ecf20Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK),
3198c2ecf20Sopenharmony_ci	/* Non IP flow, with vlan tag */
3208c2ecf20Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_TAG,
3218c2ecf20Sopenharmony_ci		       MVPP22_CLS_HEK_OPT_VLAN,
3228c2ecf20Sopenharmony_ci		       0, 0),
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ciu32 mvpp2_cls_flow_hits(struct mvpp2 *priv, int index)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CTRS_IDX, index);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return mvpp2_read(priv, MVPP2_CLS_FLOW_TBL_HIT_CTR);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_civoid mvpp2_cls_flow_read(struct mvpp2 *priv, int index,
3338c2ecf20Sopenharmony_ci			 struct mvpp2_cls_flow_entry *fe)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	fe->index = index;
3368c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, index);
3378c2ecf20Sopenharmony_ci	fe->data[0] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL0_REG);
3388c2ecf20Sopenharmony_ci	fe->data[1] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL1_REG);
3398c2ecf20Sopenharmony_ci	fe->data[2] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL2_REG);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/* Update classification flow table registers */
3438c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_write(struct mvpp2 *priv,
3448c2ecf20Sopenharmony_ci				 struct mvpp2_cls_flow_entry *fe)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index);
3478c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]);
3488c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]);
3498c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ciu32 mvpp2_cls_lookup_hits(struct mvpp2 *priv, int index)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CTRS_IDX, index);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return mvpp2_read(priv, MVPP2_CLS_DEC_TBL_HIT_CTR);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_civoid mvpp2_cls_lookup_read(struct mvpp2 *priv, int lkpid, int way,
3608c2ecf20Sopenharmony_ci			   struct mvpp2_cls_lookup_entry *le)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	u32 val;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	val = (way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | lkpid;
3658c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);
3668c2ecf20Sopenharmony_ci	le->way = way;
3678c2ecf20Sopenharmony_ci	le->lkpid = lkpid;
3688c2ecf20Sopenharmony_ci	le->data = mvpp2_read(priv, MVPP2_CLS_LKP_TBL_REG);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/* Update classification lookup table register */
3728c2ecf20Sopenharmony_cistatic void mvpp2_cls_lookup_write(struct mvpp2 *priv,
3738c2ecf20Sopenharmony_ci				   struct mvpp2_cls_lookup_entry *le)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	u32 val;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid;
3788c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);
3798c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/* Operations on flow entry */
3838c2ecf20Sopenharmony_cistatic int mvpp2_cls_flow_hek_num_get(struct mvpp2_cls_flow_entry *fe)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	return fe->data[1] & MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_hek_num_set(struct mvpp2_cls_flow_entry *fe,
3898c2ecf20Sopenharmony_ci				       int num_of_fields)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;
3928c2ecf20Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_N_FIELDS(num_of_fields);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic int mvpp2_cls_flow_hek_get(struct mvpp2_cls_flow_entry *fe,
3968c2ecf20Sopenharmony_ci				  int field_index)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	return (fe->data[2] >> MVPP2_CLS_FLOW_TBL2_FLD_OFFS(field_index)) &
3998c2ecf20Sopenharmony_ci		MVPP2_CLS_FLOW_TBL2_FLD_MASK;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_hek_set(struct mvpp2_cls_flow_entry *fe,
4038c2ecf20Sopenharmony_ci				   int field_index, int field_id)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	fe->data[2] &= ~MVPP2_CLS_FLOW_TBL2_FLD(field_index,
4068c2ecf20Sopenharmony_ci						MVPP2_CLS_FLOW_TBL2_FLD_MASK);
4078c2ecf20Sopenharmony_ci	fe->data[2] |= MVPP2_CLS_FLOW_TBL2_FLD(field_index, field_id);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_eng_set(struct mvpp2_cls_flow_entry *fe,
4118c2ecf20Sopenharmony_ci				   int engine)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_ENG(MVPP2_CLS_FLOW_TBL0_ENG_MASK);
4148c2ecf20Sopenharmony_ci	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_ENG(engine);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ciint mvpp2_cls_flow_eng_get(struct mvpp2_cls_flow_entry *fe)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	return (fe->data[0] >> MVPP2_CLS_FLOW_TBL0_OFFS) &
4208c2ecf20Sopenharmony_ci		MVPP2_CLS_FLOW_TBL0_ENG_MASK;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_port_id_sel(struct mvpp2_cls_flow_entry *fe,
4248c2ecf20Sopenharmony_ci				       bool from_packet)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	if (from_packet)
4278c2ecf20Sopenharmony_ci		fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
4288c2ecf20Sopenharmony_ci	else
4298c2ecf20Sopenharmony_ci		fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_last_set(struct mvpp2_cls_flow_entry *fe,
4338c2ecf20Sopenharmony_ci				    bool is_last)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_LAST;
4368c2ecf20Sopenharmony_ci	fe->data[0] |= !!is_last;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_pri_set(struct mvpp2_cls_flow_entry *fe, int prio)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_PRIO(MVPP2_CLS_FLOW_TBL1_PRIO_MASK);
4428c2ecf20Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_PRIO(prio);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe,
4468c2ecf20Sopenharmony_ci				    u32 port)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_port_remove(struct mvpp2_cls_flow_entry *fe,
4528c2ecf20Sopenharmony_ci				       u32 port)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe,
4588c2ecf20Sopenharmony_ci				       u8 lu_type)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK);
4618c2ecf20Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_LU_TYPE(lu_type);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci/* Initialize the parser entry for the given flow */
4658c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_prs_init(struct mvpp2 *priv,
4668c2ecf20Sopenharmony_ci				    const struct mvpp2_cls_flow *flow)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	mvpp2_prs_add_flow(priv, flow->flow_id, flow->prs_ri.ri,
4698c2ecf20Sopenharmony_ci			   flow->prs_ri.ri_mask);
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci/* Initialize the Lookup Id table entry for the given flow */
4738c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,
4748c2ecf20Sopenharmony_ci				    const struct mvpp2_cls_flow *flow)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	le.way = 0;
4798c2ecf20Sopenharmony_ci	le.lkpid = flow->flow_id;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* The default RxQ for this port is set in the C2 lookup */
4828c2ecf20Sopenharmony_ci	le.data = 0;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* We point on the first lookup in the sequence for the flow, that is
4858c2ecf20Sopenharmony_ci	 * the C2 lookup.
4868c2ecf20Sopenharmony_ci	 */
4878c2ecf20Sopenharmony_ci	le.data |= MVPP2_CLS_LKP_FLOW_PTR(MVPP2_CLS_FLT_FIRST(flow->flow_id));
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* CLS is always enabled, RSS is enabled/disabled in C2 lookup */
4908c2ecf20Sopenharmony_ci	le.data |= MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	mvpp2_cls_lookup_write(priv, &le);
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic void mvpp2_cls_c2_write(struct mvpp2 *priv,
4968c2ecf20Sopenharmony_ci			       struct mvpp2_cls_c2_entry *c2)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	u32 val;
4998c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
5028c2ecf20Sopenharmony_ci	if (c2->valid)
5038c2ecf20Sopenharmony_ci		val &= ~MVPP22_CLS_C2_TCAM_INV_BIT;
5048c2ecf20Sopenharmony_ci	else
5058c2ecf20Sopenharmony_ci		val |= MVPP22_CLS_C2_TCAM_INV_BIT;
5068c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_INV, val);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);
5118c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);
5128c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);
5138c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);
5168c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);
5178c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);
5188c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);
5198c2ecf20Sopenharmony_ci	/* Writing TCAM_DATA4 flushes writes to TCAM_DATA0-4 and INV to HW */
5208c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_civoid mvpp2_cls_c2_read(struct mvpp2 *priv, int index,
5248c2ecf20Sopenharmony_ci		       struct mvpp2_cls_c2_entry *c2)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	u32 val;
5278c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, index);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	c2->index = index;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	c2->tcam[0] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA0);
5328c2ecf20Sopenharmony_ci	c2->tcam[1] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA1);
5338c2ecf20Sopenharmony_ci	c2->tcam[2] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA2);
5348c2ecf20Sopenharmony_ci	c2->tcam[3] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA3);
5358c2ecf20Sopenharmony_ci	c2->tcam[4] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA4);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	c2->act = mvpp2_read(priv, MVPP22_CLS_C2_ACT);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	c2->attr[0] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR0);
5408c2ecf20Sopenharmony_ci	c2->attr[1] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR1);
5418c2ecf20Sopenharmony_ci	c2->attr[2] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR2);
5428c2ecf20Sopenharmony_ci	c2->attr[3] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR3);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
5458c2ecf20Sopenharmony_ci	c2->valid = !(val & MVPP22_CLS_C2_TCAM_INV_BIT);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int mvpp2_cls_ethtool_flow_to_type(int flow_type)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	switch (flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
5518c2ecf20Sopenharmony_ci	case ETHER_FLOW:
5528c2ecf20Sopenharmony_ci		return MVPP22_FLOW_ETHERNET;
5538c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
5548c2ecf20Sopenharmony_ci		return MVPP22_FLOW_TCP4;
5558c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
5568c2ecf20Sopenharmony_ci		return MVPP22_FLOW_TCP6;
5578c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
5588c2ecf20Sopenharmony_ci		return MVPP22_FLOW_UDP4;
5598c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
5608c2ecf20Sopenharmony_ci		return MVPP22_FLOW_UDP6;
5618c2ecf20Sopenharmony_ci	case IPV4_FLOW:
5628c2ecf20Sopenharmony_ci		return MVPP22_FLOW_IP4;
5638c2ecf20Sopenharmony_ci	case IPV6_FLOW:
5648c2ecf20Sopenharmony_ci		return MVPP22_FLOW_IP6;
5658c2ecf20Sopenharmony_ci	default:
5668c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic int mvpp2_cls_c2_port_flow_index(struct mvpp2_port *port, int loc)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	return MVPP22_CLS_C2_RFS_LOC(port->id, loc);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/* Initialize the flow table entries for the given flow */
5768c2ecf20Sopenharmony_cistatic void mvpp2_cls_flow_init(struct mvpp2 *priv,
5778c2ecf20Sopenharmony_ci				const struct mvpp2_cls_flow *flow)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
5808c2ecf20Sopenharmony_ci	int i, pri = 0;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Assign default values to all entries in the flow */
5838c2ecf20Sopenharmony_ci	for (i = MVPP2_CLS_FLT_FIRST(flow->flow_id);
5848c2ecf20Sopenharmony_ci	     i <= MVPP2_CLS_FLT_LAST(flow->flow_id); i++) {
5858c2ecf20Sopenharmony_ci		memset(&fe, 0, sizeof(fe));
5868c2ecf20Sopenharmony_ci		fe.index = i;
5878c2ecf20Sopenharmony_ci		mvpp2_cls_flow_pri_set(&fe, pri++);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		if (i == MVPP2_CLS_FLT_LAST(flow->flow_id))
5908c2ecf20Sopenharmony_ci			mvpp2_cls_flow_last_set(&fe, 1);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/* RSS config C2 lookup */
5968c2ecf20Sopenharmony_ci	mvpp2_cls_flow_read(priv, MVPP2_CLS_FLT_C2_RSS_ENTRY(flow->flow_id),
5978c2ecf20Sopenharmony_ci			    &fe);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);
6008c2ecf20Sopenharmony_ci	mvpp2_cls_flow_port_id_sel(&fe, true);
6018c2ecf20Sopenharmony_ci	mvpp2_cls_flow_lu_type_set(&fe, MVPP22_CLS_LU_TYPE_ALL);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* Add all ports */
6048c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_PORTS; i++)
6058c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, BIT(i));
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	mvpp2_cls_flow_write(priv, &fe);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* C3Hx lookups */
6108c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_PORTS; i++) {
6118c2ecf20Sopenharmony_ci		mvpp2_cls_flow_read(priv,
6128c2ecf20Sopenharmony_ci				    MVPP2_CLS_FLT_HASH_ENTRY(i, flow->flow_id),
6138c2ecf20Sopenharmony_ci				    &fe);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		/* Set a default engine. Will be overwritten when setting the
6168c2ecf20Sopenharmony_ci		 * real HEK parameters
6178c2ecf20Sopenharmony_ci		 */
6188c2ecf20Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C3HA);
6198c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_id_sel(&fe, true);
6208c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, BIT(i));
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/* Adds a field to the Header Extracted Key generation parameters*/
6278c2ecf20Sopenharmony_cistatic int mvpp2_flow_add_hek_field(struct mvpp2_cls_flow_entry *fe,
6288c2ecf20Sopenharmony_ci				    u32 field_id)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	int nb_fields = mvpp2_cls_flow_hek_num_get(fe);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (nb_fields == MVPP2_FLOW_N_FIELDS)
6338c2ecf20Sopenharmony_ci		return -EINVAL;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	mvpp2_cls_flow_hek_set(fe, nb_fields, field_id);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	mvpp2_cls_flow_hek_num_set(fe, nb_fields + 1);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
6438c2ecf20Sopenharmony_ci				     unsigned long hash_opts)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	u32 field_id;
6468c2ecf20Sopenharmony_ci	int i;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* Clear old fields */
6498c2ecf20Sopenharmony_ci	mvpp2_cls_flow_hek_num_set(fe, 0);
6508c2ecf20Sopenharmony_ci	fe->data[2] = 0;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {
6538c2ecf20Sopenharmony_ci		switch (BIT(i)) {
6548c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_MAC_DA:
6558c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_MAC_DA;
6568c2ecf20Sopenharmony_ci			break;
6578c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN:
6588c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_VLAN;
6598c2ecf20Sopenharmony_ci			break;
6608c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN_PRI:
6618c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_VLAN_PRI;
6628c2ecf20Sopenharmony_ci			break;
6638c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4SA:
6648c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP4SA;
6658c2ecf20Sopenharmony_ci			break;
6668c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4DA:
6678c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP4DA;
6688c2ecf20Sopenharmony_ci			break;
6698c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6SA:
6708c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP6SA;
6718c2ecf20Sopenharmony_ci			break;
6728c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6DA:
6738c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP6DA;
6748c2ecf20Sopenharmony_ci			break;
6758c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4SIP:
6768c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_L4SIP;
6778c2ecf20Sopenharmony_ci			break;
6788c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4DIP:
6798c2ecf20Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_L4DIP;
6808c2ecf20Sopenharmony_ci			break;
6818c2ecf20Sopenharmony_ci		default:
6828c2ecf20Sopenharmony_ci			return -EINVAL;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci		if (mvpp2_flow_add_hek_field(fe, field_id))
6858c2ecf20Sopenharmony_ci			return -EINVAL;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return 0;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci/* Returns the size, in bits, of the corresponding HEK field */
6928c2ecf20Sopenharmony_cistatic int mvpp2_cls_hek_field_size(u32 field)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	switch (field) {
6958c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_MAC_DA:
6968c2ecf20Sopenharmony_ci		return 48;
6978c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_VLAN:
6988c2ecf20Sopenharmony_ci		return 12;
6998c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_VLAN_PRI:
7008c2ecf20Sopenharmony_ci		return 3;
7018c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP4SA:
7028c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP4DA:
7038c2ecf20Sopenharmony_ci		return 32;
7048c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP6SA:
7058c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP6DA:
7068c2ecf20Sopenharmony_ci		return 128;
7078c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_L4SIP:
7088c2ecf20Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_L4DIP:
7098c2ecf20Sopenharmony_ci		return 16;
7108c2ecf20Sopenharmony_ci	default:
7118c2ecf20Sopenharmony_ci		return -1;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ciconst struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	if (flow >= MVPP2_N_PRS_FLOWS)
7188c2ecf20Sopenharmony_ci		return NULL;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	return &cls_flows[flow];
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci/* Set the hash generation options for the given traffic flow.
7248c2ecf20Sopenharmony_ci * One traffic flow (in the ethtool sense) has multiple classification flows,
7258c2ecf20Sopenharmony_ci * to handle specific cases such as fragmentation, or the presence of a
7268c2ecf20Sopenharmony_ci * VLAN / DSA Tag.
7278c2ecf20Sopenharmony_ci *
7288c2ecf20Sopenharmony_ci * Each of these individual flows has different constraints, for example we
7298c2ecf20Sopenharmony_ci * can't hash fragmented packets on L4 data (else we would risk having packet
7308c2ecf20Sopenharmony_ci * re-ordering), so each classification flows masks the options with their
7318c2ecf20Sopenharmony_ci * supported ones.
7328c2ecf20Sopenharmony_ci *
7338c2ecf20Sopenharmony_ci */
7348c2ecf20Sopenharmony_cistatic int mvpp2_port_rss_hash_opts_set(struct mvpp2_port *port, int flow_type,
7358c2ecf20Sopenharmony_ci					u16 requested_opts)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
7388c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
7398c2ecf20Sopenharmony_ci	int i, engine, flow_index;
7408c2ecf20Sopenharmony_ci	u16 hash_opts;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	for_each_cls_flow_id_with_type(i, flow_type) {
7438c2ecf20Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
7448c2ecf20Sopenharmony_ci		if (!flow)
7458c2ecf20Sopenharmony_ci			return -EINVAL;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, flow_index, &fe);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		hash_opts = flow->supported_hash_opts & requested_opts;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		/* Use C3HB engine to access L4 infos. This adds L4 infos to the
7548c2ecf20Sopenharmony_ci		 * hash parameters
7558c2ecf20Sopenharmony_ci		 */
7568c2ecf20Sopenharmony_ci		if (hash_opts & MVPP22_CLS_HEK_L4_OPTS)
7578c2ecf20Sopenharmony_ci			engine = MVPP22_CLS_ENGINE_C3HB;
7588c2ecf20Sopenharmony_ci		else
7598c2ecf20Sopenharmony_ci			engine = MVPP22_CLS_ENGINE_C3HA;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		if (mvpp2_flow_set_hek_fields(&fe, hash_opts))
7628c2ecf20Sopenharmony_ci			return -EINVAL;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, engine);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(port->priv, &fe);
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return 0;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ciu16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	u16 hash_opts = 0;
7758c2ecf20Sopenharmony_ci	int n_fields, i, field;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	n_fields = mvpp2_cls_flow_hek_num_get(fe);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	for (i = 0; i < n_fields; i++) {
7808c2ecf20Sopenharmony_ci		field = mvpp2_cls_flow_hek_get(fe, i);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		switch (field) {
7838c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_MAC_DA:
7848c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;
7858c2ecf20Sopenharmony_ci			break;
7868c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_VLAN:
7878c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;
7888c2ecf20Sopenharmony_ci			break;
7898c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_VLAN_PRI:
7908c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
7918c2ecf20Sopenharmony_ci			break;
7928c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_L3_PROTO:
7938c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;
7948c2ecf20Sopenharmony_ci			break;
7958c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_IP4SA:
7968c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP4SA;
7978c2ecf20Sopenharmony_ci			break;
7988c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_IP4DA:
7998c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP4DA;
8008c2ecf20Sopenharmony_ci			break;
8018c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_IP6SA:
8028c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP6SA;
8038c2ecf20Sopenharmony_ci			break;
8048c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_IP6DA:
8058c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP6DA;
8068c2ecf20Sopenharmony_ci			break;
8078c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_L4SIP:
8088c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;
8098c2ecf20Sopenharmony_ci			break;
8108c2ecf20Sopenharmony_ci		case MVPP22_CLS_FIELD_L4DIP:
8118c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;
8128c2ecf20Sopenharmony_ci			break;
8138c2ecf20Sopenharmony_ci		default:
8148c2ecf20Sopenharmony_ci			break;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci	return hash_opts;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci/* Returns the hash opts for this flow. There are several classifier flows
8218c2ecf20Sopenharmony_ci * for one traffic flow, this returns an aggregation of all configurations.
8228c2ecf20Sopenharmony_ci */
8238c2ecf20Sopenharmony_cistatic u16 mvpp2_port_rss_hash_opts_get(struct mvpp2_port *port, int flow_type)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
8268c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
8278c2ecf20Sopenharmony_ci	int i, flow_index;
8288c2ecf20Sopenharmony_ci	u16 hash_opts = 0;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	for_each_cls_flow_id_with_type(i, flow_type) {
8318c2ecf20Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
8328c2ecf20Sopenharmony_ci		if (!flow)
8338c2ecf20Sopenharmony_ci			return 0;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, flow_index, &fe);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		hash_opts |= mvpp2_flow_get_hek_fields(&fe);
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	return hash_opts;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic void mvpp2_cls_port_init_flows(struct mvpp2 *priv)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
8488c2ecf20Sopenharmony_ci	int i;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
8518c2ecf20Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
8528c2ecf20Sopenharmony_ci		if (!flow)
8538c2ecf20Sopenharmony_ci			break;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci		mvpp2_cls_flow_prs_init(priv, flow);
8568c2ecf20Sopenharmony_ci		mvpp2_cls_flow_lkp_init(priv, flow);
8578c2ecf20Sopenharmony_ci		mvpp2_cls_flow_init(priv, flow);
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_cistatic void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
8648c2ecf20Sopenharmony_ci	u8 qh, ql, pmap;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	c2.index = MVPP22_CLS_C2_RSS_ENTRY(port->id);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	pmap = BIT(port->id);
8718c2ecf20Sopenharmony_ci	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
8728c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* Match on Lookup Type */
8758c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
8768c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP22_CLS_LU_TYPE_ALL);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* Update RSS status after matching this entry */
8798c2ecf20Sopenharmony_ci	c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	/* Mark packet as "forwarded to software", needed for RSS */
8828c2ecf20Sopenharmony_ci	c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	/* Configure the default rx queue : Update Queue Low and Queue High, but
8858c2ecf20Sopenharmony_ci	 * don't lock, since the rx queue selection might be overridden by RSS
8868c2ecf20Sopenharmony_ci	 */
8878c2ecf20Sopenharmony_ci	c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD) |
8888c2ecf20Sopenharmony_ci		   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
8918c2ecf20Sopenharmony_ci	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
8948c2ecf20Sopenharmony_ci		      MVPP22_CLS_C2_ATTR0_QLOW(ql);
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	c2.valid = true;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci/* Classifier default initialization */
9028c2ecf20Sopenharmony_civoid mvpp2_cls_init(struct mvpp2 *priv)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
9058c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
9068c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
9078c2ecf20Sopenharmony_ci	int index;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Enable classifier */
9108c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* Clear classifier flow table */
9138c2ecf20Sopenharmony_ci	memset(&fe.data, 0, sizeof(fe.data));
9148c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
9158c2ecf20Sopenharmony_ci		fe.index = index;
9168c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* Clear classifier lookup table */
9208c2ecf20Sopenharmony_ci	le.data = 0;
9218c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) {
9228c2ecf20Sopenharmony_ci		le.lkpid = index;
9238c2ecf20Sopenharmony_ci		le.way = 0;
9248c2ecf20Sopenharmony_ci		mvpp2_cls_lookup_write(priv, &le);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		le.way = 1;
9278c2ecf20Sopenharmony_ci		mvpp2_cls_lookup_write(priv, &le);
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	/* Clear C2 TCAM engine table */
9318c2ecf20Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
9328c2ecf20Sopenharmony_ci	c2.valid = false;
9338c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP22_CLS_C2_N_ENTRIES; index++) {
9348c2ecf20Sopenharmony_ci		c2.index = index;
9358c2ecf20Sopenharmony_ci		mvpp2_cls_c2_write(priv, &c2);
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* Disable the FIFO stages in C2 engine, which are only used in BIST
9398c2ecf20Sopenharmony_ci	 * mode
9408c2ecf20Sopenharmony_ci	 */
9418c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_CTRL,
9428c2ecf20Sopenharmony_ci		    MVPP22_CLS_C2_TCAM_BYPASS_FIFO);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	mvpp2_cls_port_init_flows(priv);
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_civoid mvpp2_cls_port_config(struct mvpp2_port *port)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
9508c2ecf20Sopenharmony_ci	u32 val;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/* Set way for the port */
9538c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG);
9548c2ecf20Sopenharmony_ci	val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id);
9558c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	/* Pick the entry to be accessed in lookup ID decoding table
9588c2ecf20Sopenharmony_ci	 * according to the way and lkpid.
9598c2ecf20Sopenharmony_ci	 */
9608c2ecf20Sopenharmony_ci	le.lkpid = port->id;
9618c2ecf20Sopenharmony_ci	le.way = 0;
9628c2ecf20Sopenharmony_ci	le.data = 0;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	/* Set initial CPU queue for receiving packets */
9658c2ecf20Sopenharmony_ci	le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
9668c2ecf20Sopenharmony_ci	le.data |= port->first_rxq;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	/* Disable classification engines */
9698c2ecf20Sopenharmony_ci	le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	/* Update lookup ID table entry */
9728c2ecf20Sopenharmony_ci	mvpp2_cls_lookup_write(port->priv, &le);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	mvpp2_port_c2_cls_init(port);
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ciu32 mvpp2_cls_c2_hit_count(struct mvpp2 *priv, int c2_index)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2_index);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return mvpp2_read(priv, MVPP22_CLS_C2_HIT_CTR);
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cistatic void mvpp2_rss_port_c2_enable(struct mvpp2_port *port, u32 ctx)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
9878c2ecf20Sopenharmony_ci	u8 qh, ql;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	/* The RxQ number is used to select the RSS table. It that case, we set
9928c2ecf20Sopenharmony_ci	 * it to be the ctx number.
9938c2ecf20Sopenharmony_ci	 */
9948c2ecf20Sopenharmony_ci	qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
9958c2ecf20Sopenharmony_ci	ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
9988c2ecf20Sopenharmony_ci		     MVPP22_CLS_C2_ATTR0_QLOW(ql);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic void mvpp2_rss_port_c2_disable(struct mvpp2_port *port)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
10088c2ecf20Sopenharmony_ci	u8 qh, ql;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* Reset the default destination RxQ to the port's first rx queue. */
10138c2ecf20Sopenharmony_ci	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
10148c2ecf20Sopenharmony_ci	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
10178c2ecf20Sopenharmony_ci		      MVPP22_CLS_C2_ATTR0_QLOW(ql);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	c2.attr[2] &= ~MVPP22_CLS_C2_ATTR2_RSS_EN;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_cistatic inline int mvpp22_rss_ctx(struct mvpp2_port *port, int port_rss_ctx)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	return port->rss_ctx[port_rss_ctx];
10278c2ecf20Sopenharmony_ci}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ciint mvpp22_port_rss_enable(struct mvpp2_port *port)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	if (mvpp22_rss_ctx(port, 0) < 0)
10328c2ecf20Sopenharmony_ci		return -EINVAL;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	mvpp2_rss_port_c2_enable(port, mvpp22_rss_ctx(port, 0));
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	return 0;
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ciint mvpp22_port_rss_disable(struct mvpp2_port *port)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	if (mvpp22_rss_ctx(port, 0) < 0)
10428c2ecf20Sopenharmony_ci		return -EINVAL;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	mvpp2_rss_port_c2_disable(port);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	return 0;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_cistatic void mvpp22_port_c2_lookup_disable(struct mvpp2_port *port, int entry)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, entry, &c2);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Clear the port map so that the entry doesn't match anymore */
10568c2ecf20Sopenharmony_ci	c2.tcam[4] &= ~(MVPP22_CLS_C2_PORT_ID(BIT(port->id)));
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/* Set CPU queue number for oversize packets */
10628c2ecf20Sopenharmony_civoid mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	u32 val;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id),
10678c2ecf20Sopenharmony_ci		    port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id),
10708c2ecf20Sopenharmony_ci		    (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS));
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG);
10738c2ecf20Sopenharmony_ci	val &= ~MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);
10748c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val);
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_cistatic int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
10788c2ecf20Sopenharmony_ci				       struct mvpp2_rfs_rule *rule)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	struct flow_action_entry *act;
10818c2ecf20Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
10828c2ecf20Sopenharmony_ci	u8 qh, ql, pmap;
10838c2ecf20Sopenharmony_ci	int index, ctx;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))
10868c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	index = mvpp2_cls_c2_port_flow_index(port, rule->loc);
10918c2ecf20Sopenharmony_ci	if (index < 0)
10928c2ecf20Sopenharmony_ci		return -EINVAL;
10938c2ecf20Sopenharmony_ci	c2.index = index;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	act = &rule->flow->action.entries[0];
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	rule->c2_index = c2.index;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	c2.tcam[3] = (rule->c2_tcam & 0xffff) |
11008c2ecf20Sopenharmony_ci		     ((rule->c2_tcam_mask & 0xffff) << 16);
11018c2ecf20Sopenharmony_ci	c2.tcam[2] = ((rule->c2_tcam >> 16) & 0xffff) |
11028c2ecf20Sopenharmony_ci		     (((rule->c2_tcam_mask >> 16) & 0xffff) << 16);
11038c2ecf20Sopenharmony_ci	c2.tcam[1] = ((rule->c2_tcam >> 32) & 0xffff) |
11048c2ecf20Sopenharmony_ci		     (((rule->c2_tcam_mask >> 32) & 0xffff) << 16);
11058c2ecf20Sopenharmony_ci	c2.tcam[0] = ((rule->c2_tcam >> 48) & 0xffff) |
11068c2ecf20Sopenharmony_ci		     (((rule->c2_tcam_mask >> 48) & 0xffff) << 16);
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	pmap = BIT(port->id);
11098c2ecf20Sopenharmony_ci	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
11108c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	/* Match on Lookup Type */
11138c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
11148c2ecf20Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(rule->loc);
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	if (act->id == FLOW_ACTION_DROP) {
11178c2ecf20Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_RED_LOCK);
11188c2ecf20Sopenharmony_ci	} else {
11198c2ecf20Sopenharmony_ci		/* We want to keep the default color derived from the Header
11208c2ecf20Sopenharmony_ci		 * Parser drop entries, for VLAN and MAC filtering. This will
11218c2ecf20Sopenharmony_ci		 * assign a default color of Green or Red, and we want matches
11228c2ecf20Sopenharmony_ci		 * with a non-drop action to keep that color.
11238c2ecf20Sopenharmony_ci		 */
11248c2ecf20Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_NO_UPD_LOCK);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci		/* Update RSS status after matching this entry */
11278c2ecf20Sopenharmony_ci		if (act->queue.ctx)
11288c2ecf20Sopenharmony_ci			c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci		/* Always lock the RSS_EN decision. We might have high prio
11318c2ecf20Sopenharmony_ci		 * rules steering to an RXQ, and a lower one steering to RSS,
11328c2ecf20Sopenharmony_ci		 * we don't want the low prio RSS rule overwriting this flag.
11338c2ecf20Sopenharmony_ci		 */
11348c2ecf20Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci		/* Mark packet as "forwarded to software", needed for RSS */
11378c2ecf20Sopenharmony_ci		c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD_LOCK) |
11408c2ecf20Sopenharmony_ci			   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD_LOCK);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		if (act->queue.ctx) {
11438c2ecf20Sopenharmony_ci			/* Get the global ctx number */
11448c2ecf20Sopenharmony_ci			ctx = mvpp22_rss_ctx(port, act->queue.ctx);
11458c2ecf20Sopenharmony_ci			if (ctx < 0)
11468c2ecf20Sopenharmony_ci				return -EINVAL;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci			qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
11498c2ecf20Sopenharmony_ci			ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
11508c2ecf20Sopenharmony_ci		} else {
11518c2ecf20Sopenharmony_ci			qh = ((act->queue.index + port->first_rxq) >> 3) &
11528c2ecf20Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
11538c2ecf20Sopenharmony_ci			ql = (act->queue.index + port->first_rxq) &
11548c2ecf20Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QLOW_MASK;
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
11588c2ecf20Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QLOW(ql);
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	c2.valid = true;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int mvpp2_port_c2_rfs_rule_insert(struct mvpp2_port *port,
11698c2ecf20Sopenharmony_ci					 struct mvpp2_rfs_rule *rule)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	return mvpp2_port_c2_tcam_rule_add(port, rule);
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistatic int mvpp2_port_cls_rfs_rule_remove(struct mvpp2_port *port,
11758c2ecf20Sopenharmony_ci					  struct mvpp2_rfs_rule *rule)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
11788c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
11798c2ecf20Sopenharmony_ci	int index, i;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	for_each_cls_flow_id_containing_type(i, rule->flow_type) {
11828c2ecf20Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
11838c2ecf20Sopenharmony_ci		if (!flow)
11848c2ecf20Sopenharmony_ci			return 0;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, index, &fe);
11898c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_remove(&fe, BIT(port->id));
11908c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(port->priv, &fe);
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	if (rule->c2_index >= 0)
11948c2ecf20Sopenharmony_ci		mvpp22_port_c2_lookup_disable(port, rule->c2_index);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	return 0;
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port,
12008c2ecf20Sopenharmony_ci					  struct mvpp2_rfs_rule *rule)
12018c2ecf20Sopenharmony_ci{
12028c2ecf20Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
12038c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
12048c2ecf20Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
12058c2ecf20Sopenharmony_ci	int index, ret, i;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	if (rule->engine != MVPP22_CLS_ENGINE_C2)
12088c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	ret = mvpp2_port_c2_rfs_rule_insert(port, rule);
12118c2ecf20Sopenharmony_ci	if (ret)
12128c2ecf20Sopenharmony_ci		return ret;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	for_each_cls_flow_id_containing_type(i, rule->flow_type) {
12158c2ecf20Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
12168c2ecf20Sopenharmony_ci		if (!flow)
12178c2ecf20Sopenharmony_ci			return 0;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		if ((rule->hek_fields & flow->supported_hash_opts) != rule->hek_fields)
12208c2ecf20Sopenharmony_ci			continue;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci		mvpp2_cls_flow_read(priv, index, &fe);
12258c2ecf20Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, rule->engine);
12268c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_id_sel(&fe, true);
12278c2ecf20Sopenharmony_ci		mvpp2_flow_set_hek_fields(&fe, rule->hek_fields);
12288c2ecf20Sopenharmony_ci		mvpp2_cls_flow_lu_type_set(&fe, rule->loc);
12298c2ecf20Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, 0xf);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	return 0;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	struct flow_rule *flow = rule->flow;
12408c2ecf20Sopenharmony_ci	int offs = 0;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	/* The order of insertion in C2 tcam must match the order in which
12438c2ecf20Sopenharmony_ci	 * the fields are found in the header
12448c2ecf20Sopenharmony_ci	 */
12458c2ecf20Sopenharmony_ci	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_VLAN)) {
12468c2ecf20Sopenharmony_ci		struct flow_match_vlan match;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci		flow_rule_match_vlan(flow, &match);
12498c2ecf20Sopenharmony_ci		if (match.mask->vlan_id) {
12508c2ecf20Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci			rule->c2_tcam |= ((u64)match.key->vlan_id) << offs;
12538c2ecf20Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)match.mask->vlan_id) << offs;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci			/* Don't update the offset yet */
12568c2ecf20Sopenharmony_ci		}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		if (match.mask->vlan_priority) {
12598c2ecf20Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci			/* VLAN pri is always at offset 13 relative to the
12628c2ecf20Sopenharmony_ci			 * current offset
12638c2ecf20Sopenharmony_ci			 */
12648c2ecf20Sopenharmony_ci			rule->c2_tcam |= ((u64)match.key->vlan_priority) <<
12658c2ecf20Sopenharmony_ci				(offs + 13);
12668c2ecf20Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)match.mask->vlan_priority) <<
12678c2ecf20Sopenharmony_ci				(offs + 13);
12688c2ecf20Sopenharmony_ci		}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		if (match.mask->vlan_dei)
12718c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci		/* vlan id and prio always seem to take a full 16-bit slot in
12748c2ecf20Sopenharmony_ci		 * the Header Extracted Key.
12758c2ecf20Sopenharmony_ci		 */
12768c2ecf20Sopenharmony_ci		offs += 16;
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) {
12808c2ecf20Sopenharmony_ci		struct flow_match_ports match;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci		flow_rule_match_ports(flow, &match);
12838c2ecf20Sopenharmony_ci		if (match.mask->src) {
12848c2ecf20Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4SIP;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci			rule->c2_tcam |= ((u64)ntohs(match.key->src)) << offs;
12878c2ecf20Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->src)) << offs;
12888c2ecf20Sopenharmony_ci			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP);
12898c2ecf20Sopenharmony_ci		}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		if (match.mask->dst) {
12928c2ecf20Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4DIP;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci			rule->c2_tcam |= ((u64)ntohs(match.key->dst)) << offs;
12958c2ecf20Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->dst)) << offs;
12968c2ecf20Sopenharmony_ci			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP);
12978c2ecf20Sopenharmony_ci		}
12988c2ecf20Sopenharmony_ci	}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (hweight16(rule->hek_fields) > MVPP2_FLOW_N_FIELDS)
13018c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	return 0;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule)
13078c2ecf20Sopenharmony_ci{
13088c2ecf20Sopenharmony_ci	struct flow_rule *flow = rule->flow;
13098c2ecf20Sopenharmony_ci	struct flow_action_entry *act;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))
13128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	act = &flow->action.entries[0];
13158c2ecf20Sopenharmony_ci	if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
13168c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	/* When both an RSS context and an queue index are set, the index
13198c2ecf20Sopenharmony_ci	 * is considered as an offset to be added to the indirection table
13208c2ecf20Sopenharmony_ci	 * entries. We don't support this, so reject this rule.
13218c2ecf20Sopenharmony_ci	 */
13228c2ecf20Sopenharmony_ci	if (act->queue.ctx && act->queue.index)
13238c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	/* For now, only use the C2 engine which has a HEK size limited to 64
13268c2ecf20Sopenharmony_ci	 * bits for TCAM matching.
13278c2ecf20Sopenharmony_ci	 */
13288c2ecf20Sopenharmony_ci	rule->engine = MVPP22_CLS_ENGINE_C2;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if (mvpp2_cls_c2_build_match(rule))
13318c2ecf20Sopenharmony_ci		return -EINVAL;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	return 0;
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ciint mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port,
13378c2ecf20Sopenharmony_ci			       struct ethtool_rxnfc *rxnfc)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct mvpp2_ethtool_fs *efs;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	if (rxnfc->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
13428c2ecf20Sopenharmony_ci		return -EINVAL;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	efs = port->rfs_rules[rxnfc->fs.location];
13458c2ecf20Sopenharmony_ci	if (!efs)
13468c2ecf20Sopenharmony_ci		return -ENOENT;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	memcpy(rxnfc, &efs->rxnfc, sizeof(efs->rxnfc));
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	return 0;
13518c2ecf20Sopenharmony_ci}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ciint mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
13548c2ecf20Sopenharmony_ci			       struct ethtool_rxnfc *info)
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec_input input = {};
13578c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_rule *ethtool_rule;
13588c2ecf20Sopenharmony_ci	struct mvpp2_ethtool_fs *efs, *old_efs;
13598c2ecf20Sopenharmony_ci	int ret = 0;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
13628c2ecf20Sopenharmony_ci		return -EINVAL;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	efs = kzalloc(sizeof(*efs), GFP_KERNEL);
13658c2ecf20Sopenharmony_ci	if (!efs)
13668c2ecf20Sopenharmony_ci		return -ENOMEM;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	input.fs = &info->fs;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* We need to manually set the rss_ctx, since this info isn't present
13718c2ecf20Sopenharmony_ci	 * in info->fs
13728c2ecf20Sopenharmony_ci	 */
13738c2ecf20Sopenharmony_ci	if (info->fs.flow_type & FLOW_RSS)
13748c2ecf20Sopenharmony_ci		input.rss_ctx = info->rss_context;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	ethtool_rule = ethtool_rx_flow_rule_create(&input);
13778c2ecf20Sopenharmony_ci	if (IS_ERR(ethtool_rule)) {
13788c2ecf20Sopenharmony_ci		ret = PTR_ERR(ethtool_rule);
13798c2ecf20Sopenharmony_ci		goto clean_rule;
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	efs->rule.flow = ethtool_rule->rule;
13838c2ecf20Sopenharmony_ci	efs->rule.flow_type = mvpp2_cls_ethtool_flow_to_type(info->fs.flow_type);
13848c2ecf20Sopenharmony_ci	if (efs->rule.flow_type < 0) {
13858c2ecf20Sopenharmony_ci		ret = efs->rule.flow_type;
13868c2ecf20Sopenharmony_ci		goto clean_rule;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	ret = mvpp2_cls_rfs_parse_rule(&efs->rule);
13908c2ecf20Sopenharmony_ci	if (ret)
13918c2ecf20Sopenharmony_ci		goto clean_eth_rule;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	efs->rule.loc = info->fs.location;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	/* Replace an already existing rule */
13968c2ecf20Sopenharmony_ci	if (port->rfs_rules[efs->rule.loc]) {
13978c2ecf20Sopenharmony_ci		old_efs = port->rfs_rules[efs->rule.loc];
13988c2ecf20Sopenharmony_ci		ret = mvpp2_port_cls_rfs_rule_remove(port, &old_efs->rule);
13998c2ecf20Sopenharmony_ci		if (ret)
14008c2ecf20Sopenharmony_ci			goto clean_eth_rule;
14018c2ecf20Sopenharmony_ci		kfree(old_efs);
14028c2ecf20Sopenharmony_ci		port->n_rfs_rules--;
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	ret = mvpp2_port_flt_rfs_rule_insert(port, &efs->rule);
14068c2ecf20Sopenharmony_ci	if (ret)
14078c2ecf20Sopenharmony_ci		goto clean_eth_rule;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	ethtool_rx_flow_rule_destroy(ethtool_rule);
14108c2ecf20Sopenharmony_ci	efs->rule.flow = NULL;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	memcpy(&efs->rxnfc, info, sizeof(*info));
14138c2ecf20Sopenharmony_ci	port->rfs_rules[efs->rule.loc] = efs;
14148c2ecf20Sopenharmony_ci	port->n_rfs_rules++;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	return ret;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ciclean_eth_rule:
14198c2ecf20Sopenharmony_ci	ethtool_rx_flow_rule_destroy(ethtool_rule);
14208c2ecf20Sopenharmony_ciclean_rule:
14218c2ecf20Sopenharmony_ci	kfree(efs);
14228c2ecf20Sopenharmony_ci	return ret;
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ciint mvpp2_ethtool_cls_rule_del(struct mvpp2_port *port,
14268c2ecf20Sopenharmony_ci			       struct ethtool_rxnfc *info)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	struct mvpp2_ethtool_fs *efs;
14298c2ecf20Sopenharmony_ci	int ret;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
14328c2ecf20Sopenharmony_ci		return -EINVAL;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	efs = port->rfs_rules[info->fs.location];
14358c2ecf20Sopenharmony_ci	if (!efs)
14368c2ecf20Sopenharmony_ci		return -EINVAL;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	/* Remove the rule from the engines. */
14398c2ecf20Sopenharmony_ci	ret = mvpp2_port_cls_rfs_rule_remove(port, &efs->rule);
14408c2ecf20Sopenharmony_ci	if (ret)
14418c2ecf20Sopenharmony_ci		return ret;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	port->n_rfs_rules--;
14448c2ecf20Sopenharmony_ci	port->rfs_rules[info->fs.location] = NULL;
14458c2ecf20Sopenharmony_ci	kfree(efs);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	return 0;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	int nrxqs, cpu, cpus = num_possible_cpus();
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	/* Number of RXQs per CPU */
14558c2ecf20Sopenharmony_ci	nrxqs = port->nrxqs / cpus;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* CPU that will handle this rx queue */
14588c2ecf20Sopenharmony_ci	cpu = rxq / nrxqs;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	if (!cpu_online(cpu))
14618c2ecf20Sopenharmony_ci		return port->first_rxq;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/* Indirection to better distribute the paquets on the CPUs when
14648c2ecf20Sopenharmony_ci	 * configuring the RSS queues.
14658c2ecf20Sopenharmony_ci	 */
14668c2ecf20Sopenharmony_ci	return port->first_rxq + ((rxq * nrxqs + rxq / cpus) % port->nrxqs);
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic void mvpp22_rss_fill_table(struct mvpp2_port *port,
14708c2ecf20Sopenharmony_ci				  struct mvpp2_rss_table *table,
14718c2ecf20Sopenharmony_ci				  u32 rss_ctx)
14728c2ecf20Sopenharmony_ci{
14738c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
14748c2ecf20Sopenharmony_ci	int i;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {
14778c2ecf20Sopenharmony_ci		u32 sel = MVPP22_RSS_INDEX_TABLE(rss_ctx) |
14788c2ecf20Sopenharmony_ci			  MVPP22_RSS_INDEX_TABLE_ENTRY(i);
14798c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_RSS_INDEX, sel);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY,
14828c2ecf20Sopenharmony_ci			    mvpp22_rxfh_indir(port, table->indir[i]));
14838c2ecf20Sopenharmony_ci	}
14848c2ecf20Sopenharmony_ci}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_cistatic int mvpp22_rss_context_create(struct mvpp2_port *port, u32 *rss_ctx)
14878c2ecf20Sopenharmony_ci{
14888c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
14898c2ecf20Sopenharmony_ci	u32 ctx;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	/* Find the first free RSS table */
14928c2ecf20Sopenharmony_ci	for (ctx = 0; ctx < MVPP22_N_RSS_TABLES; ctx++) {
14938c2ecf20Sopenharmony_ci		if (!priv->rss_tables[ctx])
14948c2ecf20Sopenharmony_ci			break;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	if (ctx == MVPP22_N_RSS_TABLES)
14988c2ecf20Sopenharmony_ci		return -EINVAL;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	priv->rss_tables[ctx] = kzalloc(sizeof(*priv->rss_tables[ctx]),
15018c2ecf20Sopenharmony_ci					GFP_KERNEL);
15028c2ecf20Sopenharmony_ci	if (!priv->rss_tables[ctx])
15038c2ecf20Sopenharmony_ci		return -ENOMEM;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	*rss_ctx = ctx;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	/* Set the table width: replace the whole classifier Rx queue number
15088c2ecf20Sopenharmony_ci	 * with the ones configured in RSS table entries.
15098c2ecf20Sopenharmony_ci	 */
15108c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(ctx));
15118c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(ctx));
15148c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_RXQ2RSS_TABLE, MVPP22_RSS_TABLE_POINTER(ctx));
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	return 0;
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ciint mvpp22_port_rss_ctx_create(struct mvpp2_port *port, u32 *port_ctx)
15208c2ecf20Sopenharmony_ci{
15218c2ecf20Sopenharmony_ci	u32 rss_ctx;
15228c2ecf20Sopenharmony_ci	int ret, i;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	ret = mvpp22_rss_context_create(port, &rss_ctx);
15258c2ecf20Sopenharmony_ci	if (ret)
15268c2ecf20Sopenharmony_ci		return ret;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/* Find the first available context number in the port, starting from 1.
15298c2ecf20Sopenharmony_ci	 * Context 0 on each port is reserved for the default context.
15308c2ecf20Sopenharmony_ci	 */
15318c2ecf20Sopenharmony_ci	for (i = 1; i < MVPP22_N_RSS_TABLES; i++) {
15328c2ecf20Sopenharmony_ci		if (port->rss_ctx[i] < 0)
15338c2ecf20Sopenharmony_ci			break;
15348c2ecf20Sopenharmony_ci	}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	if (i == MVPP22_N_RSS_TABLES)
15378c2ecf20Sopenharmony_ci		return -EINVAL;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	port->rss_ctx[i] = rss_ctx;
15408c2ecf20Sopenharmony_ci	*port_ctx = i;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	return 0;
15438c2ecf20Sopenharmony_ci}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_cistatic struct mvpp2_rss_table *mvpp22_rss_table_get(struct mvpp2 *priv,
15468c2ecf20Sopenharmony_ci						    int rss_ctx)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
15498c2ecf20Sopenharmony_ci		return NULL;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	return priv->rss_tables[rss_ctx];
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ciint mvpp22_port_rss_ctx_delete(struct mvpp2_port *port, u32 port_ctx)
15558c2ecf20Sopenharmony_ci{
15568c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
15578c2ecf20Sopenharmony_ci	struct ethtool_rxnfc *rxnfc;
15588c2ecf20Sopenharmony_ci	int i, rss_ctx, ret;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	rss_ctx = mvpp22_rss_ctx(port, port_ctx);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
15638c2ecf20Sopenharmony_ci		return -EINVAL;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	/* Invalidate any active classification rule that use this context */
15668c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
15678c2ecf20Sopenharmony_ci		if (!port->rfs_rules[i])
15688c2ecf20Sopenharmony_ci			continue;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci		rxnfc = &port->rfs_rules[i]->rxnfc;
15718c2ecf20Sopenharmony_ci		if (!(rxnfc->fs.flow_type & FLOW_RSS) ||
15728c2ecf20Sopenharmony_ci		    rxnfc->rss_context != port_ctx)
15738c2ecf20Sopenharmony_ci			continue;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_cls_rule_del(port, rxnfc);
15768c2ecf20Sopenharmony_ci		if (ret) {
15778c2ecf20Sopenharmony_ci			netdev_warn(port->dev,
15788c2ecf20Sopenharmony_ci				    "couldn't remove classification rule %d associated to this context",
15798c2ecf20Sopenharmony_ci				    rxnfc->fs.location);
15808c2ecf20Sopenharmony_ci		}
15818c2ecf20Sopenharmony_ci	}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	kfree(priv->rss_tables[rss_ctx]);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	priv->rss_tables[rss_ctx] = NULL;
15868c2ecf20Sopenharmony_ci	port->rss_ctx[port_ctx] = -1;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	return 0;
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ciint mvpp22_port_rss_ctx_indir_set(struct mvpp2_port *port, u32 port_ctx,
15928c2ecf20Sopenharmony_ci				  const u32 *indir)
15938c2ecf20Sopenharmony_ci{
15948c2ecf20Sopenharmony_ci	int rss_ctx = mvpp22_rss_ctx(port, port_ctx);
15958c2ecf20Sopenharmony_ci	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
15968c2ecf20Sopenharmony_ci								 rss_ctx);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	if (!rss_table)
15998c2ecf20Sopenharmony_ci		return -EINVAL;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	memcpy(rss_table->indir, indir,
16028c2ecf20Sopenharmony_ci	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	mvpp22_rss_fill_table(port, rss_table, rss_ctx);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	return 0;
16078c2ecf20Sopenharmony_ci}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ciint mvpp22_port_rss_ctx_indir_get(struct mvpp2_port *port, u32 port_ctx,
16108c2ecf20Sopenharmony_ci				  u32 *indir)
16118c2ecf20Sopenharmony_ci{
16128c2ecf20Sopenharmony_ci	int rss_ctx =  mvpp22_rss_ctx(port, port_ctx);
16138c2ecf20Sopenharmony_ci	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
16148c2ecf20Sopenharmony_ci								 rss_ctx);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	if (!rss_table)
16178c2ecf20Sopenharmony_ci		return -EINVAL;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	memcpy(indir, rss_table->indir,
16208c2ecf20Sopenharmony_ci	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	return 0;
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ciint mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	u16 hash_opts = 0;
16288c2ecf20Sopenharmony_ci	u32 flow_type;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	switch (flow_type) {
16338c2ecf20Sopenharmony_ci	case MVPP22_FLOW_TCP4:
16348c2ecf20Sopenharmony_ci	case MVPP22_FLOW_UDP4:
16358c2ecf20Sopenharmony_ci	case MVPP22_FLOW_TCP6:
16368c2ecf20Sopenharmony_ci	case MVPP22_FLOW_UDP6:
16378c2ecf20Sopenharmony_ci		if (info->data & RXH_L4_B_0_1)
16388c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;
16398c2ecf20Sopenharmony_ci		if (info->data & RXH_L4_B_2_3)
16408c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;
16418c2ecf20Sopenharmony_ci		fallthrough;
16428c2ecf20Sopenharmony_ci	case MVPP22_FLOW_IP4:
16438c2ecf20Sopenharmony_ci	case MVPP22_FLOW_IP6:
16448c2ecf20Sopenharmony_ci		if (info->data & RXH_L2DA)
16458c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;
16468c2ecf20Sopenharmony_ci		if (info->data & RXH_VLAN)
16478c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;
16488c2ecf20Sopenharmony_ci		if (info->data & RXH_L3_PROTO)
16498c2ecf20Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;
16508c2ecf20Sopenharmony_ci		if (info->data & RXH_IP_SRC)
16518c2ecf20Sopenharmony_ci			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4SA |
16528c2ecf20Sopenharmony_ci				     MVPP22_CLS_HEK_OPT_IP6SA);
16538c2ecf20Sopenharmony_ci		if (info->data & RXH_IP_DST)
16548c2ecf20Sopenharmony_ci			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4DA |
16558c2ecf20Sopenharmony_ci				     MVPP22_CLS_HEK_OPT_IP6DA);
16568c2ecf20Sopenharmony_ci		break;
16578c2ecf20Sopenharmony_ci	default: return -EOPNOTSUPP;
16588c2ecf20Sopenharmony_ci	}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	return mvpp2_port_rss_hash_opts_set(port, flow_type, hash_opts);
16618c2ecf20Sopenharmony_ci}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ciint mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	unsigned long hash_opts;
16668c2ecf20Sopenharmony_ci	u32 flow_type;
16678c2ecf20Sopenharmony_ci	int i;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	hash_opts = mvpp2_port_rss_hash_opts_get(port, flow_type);
16728c2ecf20Sopenharmony_ci	info->data = 0;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {
16758c2ecf20Sopenharmony_ci		switch (BIT(i)) {
16768c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_MAC_DA:
16778c2ecf20Sopenharmony_ci			info->data |= RXH_L2DA;
16788c2ecf20Sopenharmony_ci			break;
16798c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN:
16808c2ecf20Sopenharmony_ci			info->data |= RXH_VLAN;
16818c2ecf20Sopenharmony_ci			break;
16828c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L3_PROTO:
16838c2ecf20Sopenharmony_ci			info->data |= RXH_L3_PROTO;
16848c2ecf20Sopenharmony_ci			break;
16858c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4SA:
16868c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6SA:
16878c2ecf20Sopenharmony_ci			info->data |= RXH_IP_SRC;
16888c2ecf20Sopenharmony_ci			break;
16898c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4DA:
16908c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6DA:
16918c2ecf20Sopenharmony_ci			info->data |= RXH_IP_DST;
16928c2ecf20Sopenharmony_ci			break;
16938c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4SIP:
16948c2ecf20Sopenharmony_ci			info->data |= RXH_L4_B_0_1;
16958c2ecf20Sopenharmony_ci			break;
16968c2ecf20Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4DIP:
16978c2ecf20Sopenharmony_ci			info->data |= RXH_L4_B_2_3;
16988c2ecf20Sopenharmony_ci			break;
16998c2ecf20Sopenharmony_ci		default:
17008c2ecf20Sopenharmony_ci			return -EINVAL;
17018c2ecf20Sopenharmony_ci		}
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci	return 0;
17048c2ecf20Sopenharmony_ci}
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ciint mvpp22_port_rss_init(struct mvpp2_port *port)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	struct mvpp2_rss_table *table;
17098c2ecf20Sopenharmony_ci	u32 context = 0;
17108c2ecf20Sopenharmony_ci	int i, ret;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP22_N_RSS_TABLES; i++)
17138c2ecf20Sopenharmony_ci		port->rss_ctx[i] = -1;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	ret = mvpp22_rss_context_create(port, &context);
17168c2ecf20Sopenharmony_ci	if (ret)
17178c2ecf20Sopenharmony_ci		return ret;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	table = mvpp22_rss_table_get(port->priv, context);
17208c2ecf20Sopenharmony_ci	if (!table)
17218c2ecf20Sopenharmony_ci		return -EINVAL;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	port->rss_ctx[0] = context;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	/* Configure the first table to evenly distribute the packets across
17268c2ecf20Sopenharmony_ci	 * real Rx Queues. The table entries map a hash to a port Rx Queue.
17278c2ecf20Sopenharmony_ci	 */
17288c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++)
17298c2ecf20Sopenharmony_ci		table->indir[i] = ethtool_rxfh_indir_default(i, port->nrxqs);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	mvpp22_rss_fill_table(port, table, mvpp22_rss_ctx(port, 0));
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	/* Configure default flows */
17348c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP4, MVPP22_CLS_HEK_IP4_2T);
17358c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP6, MVPP22_CLS_HEK_IP6_2T);
17368c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP4, MVPP22_CLS_HEK_IP4_5T);
17378c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP6, MVPP22_CLS_HEK_IP6_5T);
17388c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP4, MVPP22_CLS_HEK_IP4_5T);
17398c2ecf20Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP6, MVPP22_CLS_HEK_IP6_5T);
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	return 0;
17428c2ecf20Sopenharmony_ci}
1743