162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * RSS and Classifier helpers for Marvell PPv2 Network Controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 Marvell
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Marcin Wojtas <mw@semihalf.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "mvpp2.h"
1162306a36Sopenharmony_ci#include "mvpp2_cls.h"
1262306a36Sopenharmony_ci#include "mvpp2_prs.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define MVPP2_DEF_FLOW(_type, _id, _opts, _ri, _ri_mask)	\
1562306a36Sopenharmony_ci{								\
1662306a36Sopenharmony_ci	.flow_type = _type,					\
1762306a36Sopenharmony_ci	.flow_id = _id,						\
1862306a36Sopenharmony_ci	.supported_hash_opts = _opts,				\
1962306a36Sopenharmony_ci	.prs_ri = {						\
2062306a36Sopenharmony_ci		.ri = _ri,					\
2162306a36Sopenharmony_ci		.ri_mask = _ri_mask				\
2262306a36Sopenharmony_ci	}							\
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
2662306a36Sopenharmony_ci	/* TCP over IPv4 flows, Not fragmented, no vlan tag */
2762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
2862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
2962306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
3062306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
3162306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
3462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
3562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
3662306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
3762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_UNTAG,
4062306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
4162306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
4262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
4362306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* TCP over IPv4 flows, Not fragmented, with vlan tag */
4662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
4762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
4862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
4962306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
5262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
5362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
5462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
5762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
5862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
5962306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* TCP over IPv4 flows, fragmented, no vlan tag */
6262306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
6362306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
6462306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
6562306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
6662306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
6962306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
7062306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
7162306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
7262306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
7562306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
7662306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
7762306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
7862306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* TCP over IPv4 flows, fragmented, with vlan tag */
8162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
8262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
8362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
8462306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_TCP,
8562306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
8862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
8962306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
9062306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_TCP,
9162306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
9462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
9562306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
9662306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_TCP,
9762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* UDP over IPv4 flows, Not fragmented, no vlan tag */
10062306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
10162306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
10262306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
10362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
10462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
10762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
10862306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
10962306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
11062306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_UNTAG,
11362306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T,
11462306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
11562306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
11662306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* UDP over IPv4 flows, Not fragmented, with vlan tag */
11962306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
12062306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
12162306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
12262306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
12562306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
12662306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
12762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
13062306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
13162306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
13262306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* UDP over IPv4 flows, fragmented, no vlan tag */
13562306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
13662306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
13762306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
13862306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
13962306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
14262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
14362306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
14462306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
14562306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
14862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
14962306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
15062306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
15162306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* UDP over IPv4 flows, fragmented, with vlan tag */
15462306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
15562306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
15662306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
15762306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_UDP,
15862306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
16162306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
16262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
16362306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_UDP,
16462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
16762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
16862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
16962306a36Sopenharmony_ci			   MVPP2_PRS_RI_L4_UDP,
17062306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* TCP over IPv6 flows, not fragmented, no vlan tag */
17362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,
17462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
17562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
17662306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
17762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_UNTAG,
18062306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
18162306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
18262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
18362306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* TCP over IPv6 flows, not fragmented, with vlan tag */
18662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
18762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
18862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_TCP,
18962306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
19262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
19362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_TCP,
19462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* TCP over IPv6 flows, fragmented, no vlan tag */
19762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,
19862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
19962306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
20062306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
20162306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_UNTAG,
20462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
20562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
20662306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
20762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* TCP over IPv6 flows, fragmented, with vlan tag */
21062306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
21162306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
21262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
21362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
21462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
21762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
21862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
21962306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_TCP,
22062306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* UDP over IPv6 flows, not fragmented, no vlan tag */
22362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,
22462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
22562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
22662306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
22762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_UNTAG,
23062306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T,
23162306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
23262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
23362306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* UDP over IPv6 flows, not fragmented, with vlan tag */
23662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
23762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
23862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_UDP,
23962306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
24262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
24362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_UDP,
24462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* UDP over IPv6 flows, fragmented, no vlan tag */
24762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,
24862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
24962306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6 |
25062306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
25162306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_UNTAG,
25462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
25562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6_EXT |
25662306a36Sopenharmony_ci		       MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
25762306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* UDP over IPv6 flows, fragmented, with vlan tag */
26062306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
26162306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
26262306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
26362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
26462306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
26762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
26862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
26962306a36Sopenharmony_ci		       MVPP2_PRS_RI_L4_UDP,
27062306a36Sopenharmony_ci		       MVPP2_PRS_IP_MASK),
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* IPv4 flows, no vlan tag */
27362306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
27462306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
27562306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4,
27662306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
27762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
27862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
27962306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT,
28062306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
28162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_UNTAG,
28262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T,
28362306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER,
28462306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* IPv4 flows, with vlan tag */
28762306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
28862306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
28962306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4,
29062306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
29162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
29262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
29362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OPT,
29462306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
29562306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
29662306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
29762306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP4_OTHER,
29862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* IPv6 flows, no vlan tag */
30162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,
30262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
30362306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,
30462306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
30562306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_UNTAG,
30662306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T,
30762306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP6,
30862306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK | MVPP2_PRS_RI_L3_PROTO_MASK),
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* IPv6 flows, with vlan tag */
31162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
31262306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
31362306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6,
31462306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
31562306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
31662306a36Sopenharmony_ci		       MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
31762306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_IP6,
31862306a36Sopenharmony_ci		       MVPP2_PRS_RI_L3_PROTO_MASK),
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Non IP flow, no vlan tag */
32162306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_UNTAG,
32262306a36Sopenharmony_ci		       0,
32362306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_NONE,
32462306a36Sopenharmony_ci		       MVPP2_PRS_RI_VLAN_MASK),
32562306a36Sopenharmony_ci	/* Non IP flow, with vlan tag */
32662306a36Sopenharmony_ci	MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_TAG,
32762306a36Sopenharmony_ci		       MVPP22_CLS_HEK_OPT_VLAN,
32862306a36Sopenharmony_ci		       0, 0),
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ciu32 mvpp2_cls_flow_hits(struct mvpp2 *priv, int index)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CTRS_IDX, index);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return mvpp2_read(priv, MVPP2_CLS_FLOW_TBL_HIT_CTR);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_civoid mvpp2_cls_flow_read(struct mvpp2 *priv, int index,
33962306a36Sopenharmony_ci			 struct mvpp2_cls_flow_entry *fe)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	fe->index = index;
34262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, index);
34362306a36Sopenharmony_ci	fe->data[0] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL0_REG);
34462306a36Sopenharmony_ci	fe->data[1] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL1_REG);
34562306a36Sopenharmony_ci	fe->data[2] = mvpp2_read(priv, MVPP2_CLS_FLOW_TBL2_REG);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/* Update classification flow table registers */
34962306a36Sopenharmony_cistatic void mvpp2_cls_flow_write(struct mvpp2 *priv,
35062306a36Sopenharmony_ci				 struct mvpp2_cls_flow_entry *fe)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index);
35362306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]);
35462306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]);
35562306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ciu32 mvpp2_cls_lookup_hits(struct mvpp2 *priv, int index)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CTRS_IDX, index);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return mvpp2_read(priv, MVPP2_CLS_DEC_TBL_HIT_CTR);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_civoid mvpp2_cls_lookup_read(struct mvpp2 *priv, int lkpid, int way,
36662306a36Sopenharmony_ci			   struct mvpp2_cls_lookup_entry *le)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	u32 val;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	val = (way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | lkpid;
37162306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);
37262306a36Sopenharmony_ci	le->way = way;
37362306a36Sopenharmony_ci	le->lkpid = lkpid;
37462306a36Sopenharmony_ci	le->data = mvpp2_read(priv, MVPP2_CLS_LKP_TBL_REG);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/* Update classification lookup table register */
37862306a36Sopenharmony_cistatic void mvpp2_cls_lookup_write(struct mvpp2 *priv,
37962306a36Sopenharmony_ci				   struct mvpp2_cls_lookup_entry *le)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	u32 val;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid;
38462306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val);
38562306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci/* Operations on flow entry */
38962306a36Sopenharmony_cistatic int mvpp2_cls_flow_hek_num_get(struct mvpp2_cls_flow_entry *fe)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	return fe->data[1] & MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void mvpp2_cls_flow_hek_num_set(struct mvpp2_cls_flow_entry *fe,
39562306a36Sopenharmony_ci				       int num_of_fields)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK;
39862306a36Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_N_FIELDS(num_of_fields);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int mvpp2_cls_flow_hek_get(struct mvpp2_cls_flow_entry *fe,
40262306a36Sopenharmony_ci				  int field_index)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	return (fe->data[2] >> MVPP2_CLS_FLOW_TBL2_FLD_OFFS(field_index)) &
40562306a36Sopenharmony_ci		MVPP2_CLS_FLOW_TBL2_FLD_MASK;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void mvpp2_cls_flow_hek_set(struct mvpp2_cls_flow_entry *fe,
40962306a36Sopenharmony_ci				   int field_index, int field_id)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	fe->data[2] &= ~MVPP2_CLS_FLOW_TBL2_FLD(field_index,
41262306a36Sopenharmony_ci						MVPP2_CLS_FLOW_TBL2_FLD_MASK);
41362306a36Sopenharmony_ci	fe->data[2] |= MVPP2_CLS_FLOW_TBL2_FLD(field_index, field_id);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void mvpp2_cls_flow_eng_set(struct mvpp2_cls_flow_entry *fe,
41762306a36Sopenharmony_ci				   int engine)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_ENG(MVPP2_CLS_FLOW_TBL0_ENG_MASK);
42062306a36Sopenharmony_ci	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_ENG(engine);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ciint mvpp2_cls_flow_eng_get(struct mvpp2_cls_flow_entry *fe)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	return (fe->data[0] >> MVPP2_CLS_FLOW_TBL0_OFFS) &
42662306a36Sopenharmony_ci		MVPP2_CLS_FLOW_TBL0_ENG_MASK;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic void mvpp2_cls_flow_port_id_sel(struct mvpp2_cls_flow_entry *fe,
43062306a36Sopenharmony_ci				       bool from_packet)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	if (from_packet)
43362306a36Sopenharmony_ci		fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
43462306a36Sopenharmony_ci	else
43562306a36Sopenharmony_ci		fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void mvpp2_cls_flow_last_set(struct mvpp2_cls_flow_entry *fe,
43962306a36Sopenharmony_ci				    bool is_last)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_LAST;
44262306a36Sopenharmony_ci	fe->data[0] |= !!is_last;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void mvpp2_cls_flow_pri_set(struct mvpp2_cls_flow_entry *fe, int prio)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_PRIO(MVPP2_CLS_FLOW_TBL1_PRIO_MASK);
44862306a36Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_PRIO(prio);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe,
45262306a36Sopenharmony_ci				    u32 port)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic void mvpp2_cls_flow_port_remove(struct mvpp2_cls_flow_entry *fe,
45862306a36Sopenharmony_ci				       u32 port)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe,
46462306a36Sopenharmony_ci				       u8 lu_type)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK);
46762306a36Sopenharmony_ci	fe->data[1] |= MVPP2_CLS_FLOW_TBL1_LU_TYPE(lu_type);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/* Initialize the parser entry for the given flow */
47162306a36Sopenharmony_cistatic void mvpp2_cls_flow_prs_init(struct mvpp2 *priv,
47262306a36Sopenharmony_ci				    const struct mvpp2_cls_flow *flow)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	mvpp2_prs_add_flow(priv, flow->flow_id, flow->prs_ri.ri,
47562306a36Sopenharmony_ci			   flow->prs_ri.ri_mask);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/* Initialize the Lookup Id table entry for the given flow */
47962306a36Sopenharmony_cistatic void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,
48062306a36Sopenharmony_ci				    const struct mvpp2_cls_flow *flow)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	le.way = 0;
48562306a36Sopenharmony_ci	le.lkpid = flow->flow_id;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/* The default RxQ for this port is set in the C2 lookup */
48862306a36Sopenharmony_ci	le.data = 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* We point on the first lookup in the sequence for the flow, that is
49162306a36Sopenharmony_ci	 * the C2 lookup.
49262306a36Sopenharmony_ci	 */
49362306a36Sopenharmony_ci	le.data |= MVPP2_CLS_LKP_FLOW_PTR(MVPP2_CLS_FLT_FIRST(flow->flow_id));
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* CLS is always enabled, RSS is enabled/disabled in C2 lookup */
49662306a36Sopenharmony_ci	le.data |= MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	mvpp2_cls_lookup_write(priv, &le);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void mvpp2_cls_c2_write(struct mvpp2 *priv,
50262306a36Sopenharmony_ci			       struct mvpp2_cls_c2_entry *c2)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	u32 val;
50562306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
50862306a36Sopenharmony_ci	if (c2->valid)
50962306a36Sopenharmony_ci		val &= ~MVPP22_CLS_C2_TCAM_INV_BIT;
51062306a36Sopenharmony_ci	else
51162306a36Sopenharmony_ci		val |= MVPP22_CLS_C2_TCAM_INV_BIT;
51262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_INV, val);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);
51762306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);
51862306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);
51962306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);
52262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);
52362306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);
52462306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);
52562306a36Sopenharmony_ci	/* Writing TCAM_DATA4 flushes writes to TCAM_DATA0-4 and INV to HW */
52662306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_civoid mvpp2_cls_c2_read(struct mvpp2 *priv, int index,
53062306a36Sopenharmony_ci		       struct mvpp2_cls_c2_entry *c2)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	u32 val;
53362306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, index);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	c2->index = index;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	c2->tcam[0] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA0);
53862306a36Sopenharmony_ci	c2->tcam[1] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA1);
53962306a36Sopenharmony_ci	c2->tcam[2] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA2);
54062306a36Sopenharmony_ci	c2->tcam[3] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA3);
54162306a36Sopenharmony_ci	c2->tcam[4] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA4);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	c2->act = mvpp2_read(priv, MVPP22_CLS_C2_ACT);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	c2->attr[0] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR0);
54662306a36Sopenharmony_ci	c2->attr[1] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR1);
54762306a36Sopenharmony_ci	c2->attr[2] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR2);
54862306a36Sopenharmony_ci	c2->attr[3] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR3);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
55162306a36Sopenharmony_ci	c2->valid = !(val & MVPP22_CLS_C2_TCAM_INV_BIT);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int mvpp2_cls_ethtool_flow_to_type(int flow_type)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	switch (flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
55762306a36Sopenharmony_ci	case ETHER_FLOW:
55862306a36Sopenharmony_ci		return MVPP22_FLOW_ETHERNET;
55962306a36Sopenharmony_ci	case TCP_V4_FLOW:
56062306a36Sopenharmony_ci		return MVPP22_FLOW_TCP4;
56162306a36Sopenharmony_ci	case TCP_V6_FLOW:
56262306a36Sopenharmony_ci		return MVPP22_FLOW_TCP6;
56362306a36Sopenharmony_ci	case UDP_V4_FLOW:
56462306a36Sopenharmony_ci		return MVPP22_FLOW_UDP4;
56562306a36Sopenharmony_ci	case UDP_V6_FLOW:
56662306a36Sopenharmony_ci		return MVPP22_FLOW_UDP6;
56762306a36Sopenharmony_ci	case IPV4_FLOW:
56862306a36Sopenharmony_ci		return MVPP22_FLOW_IP4;
56962306a36Sopenharmony_ci	case IPV6_FLOW:
57062306a36Sopenharmony_ci		return MVPP22_FLOW_IP6;
57162306a36Sopenharmony_ci	default:
57262306a36Sopenharmony_ci		return -EOPNOTSUPP;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int mvpp2_cls_c2_port_flow_index(struct mvpp2_port *port, int loc)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	return MVPP22_CLS_C2_RFS_LOC(port->id, loc);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci/* Initialize the flow table entries for the given flow */
58262306a36Sopenharmony_cistatic void mvpp2_cls_flow_init(struct mvpp2 *priv,
58362306a36Sopenharmony_ci				const struct mvpp2_cls_flow *flow)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
58662306a36Sopenharmony_ci	int i, pri = 0;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Assign default values to all entries in the flow */
58962306a36Sopenharmony_ci	for (i = MVPP2_CLS_FLT_FIRST(flow->flow_id);
59062306a36Sopenharmony_ci	     i <= MVPP2_CLS_FLT_LAST(flow->flow_id); i++) {
59162306a36Sopenharmony_ci		memset(&fe, 0, sizeof(fe));
59262306a36Sopenharmony_ci		fe.index = i;
59362306a36Sopenharmony_ci		mvpp2_cls_flow_pri_set(&fe, pri++);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		if (i == MVPP2_CLS_FLT_LAST(flow->flow_id))
59662306a36Sopenharmony_ci			mvpp2_cls_flow_last_set(&fe, 1);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* RSS config C2 lookup */
60262306a36Sopenharmony_ci	mvpp2_cls_flow_read(priv, MVPP2_CLS_FLT_C2_RSS_ENTRY(flow->flow_id),
60362306a36Sopenharmony_ci			    &fe);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);
60662306a36Sopenharmony_ci	mvpp2_cls_flow_port_id_sel(&fe, true);
60762306a36Sopenharmony_ci	mvpp2_cls_flow_lu_type_set(&fe, MVPP22_CLS_LU_TYPE_ALL);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Add all ports */
61062306a36Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_PORTS; i++)
61162306a36Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, BIT(i));
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	mvpp2_cls_flow_write(priv, &fe);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* C3Hx lookups */
61662306a36Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_PORTS; i++) {
61762306a36Sopenharmony_ci		mvpp2_cls_flow_read(priv,
61862306a36Sopenharmony_ci				    MVPP2_CLS_FLT_HASH_ENTRY(i, flow->flow_id),
61962306a36Sopenharmony_ci				    &fe);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		/* Set a default engine. Will be overwritten when setting the
62262306a36Sopenharmony_ci		 * real HEK parameters
62362306a36Sopenharmony_ci		 */
62462306a36Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C3HA);
62562306a36Sopenharmony_ci		mvpp2_cls_flow_port_id_sel(&fe, true);
62662306a36Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, BIT(i));
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/* Adds a field to the Header Extracted Key generation parameters*/
63362306a36Sopenharmony_cistatic int mvpp2_flow_add_hek_field(struct mvpp2_cls_flow_entry *fe,
63462306a36Sopenharmony_ci				    u32 field_id)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	int nb_fields = mvpp2_cls_flow_hek_num_get(fe);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (nb_fields == MVPP2_FLOW_N_FIELDS)
63962306a36Sopenharmony_ci		return -EINVAL;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	mvpp2_cls_flow_hek_set(fe, nb_fields, field_id);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	mvpp2_cls_flow_hek_num_set(fe, nb_fields + 1);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return 0;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
64962306a36Sopenharmony_ci				     unsigned long hash_opts)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	u32 field_id;
65262306a36Sopenharmony_ci	int i;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* Clear old fields */
65562306a36Sopenharmony_ci	mvpp2_cls_flow_hek_num_set(fe, 0);
65662306a36Sopenharmony_ci	fe->data[2] = 0;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {
65962306a36Sopenharmony_ci		switch (BIT(i)) {
66062306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_MAC_DA:
66162306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_MAC_DA;
66262306a36Sopenharmony_ci			break;
66362306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN:
66462306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_VLAN;
66562306a36Sopenharmony_ci			break;
66662306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN_PRI:
66762306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_VLAN_PRI;
66862306a36Sopenharmony_ci			break;
66962306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4SA:
67062306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP4SA;
67162306a36Sopenharmony_ci			break;
67262306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4DA:
67362306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP4DA;
67462306a36Sopenharmony_ci			break;
67562306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6SA:
67662306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP6SA;
67762306a36Sopenharmony_ci			break;
67862306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6DA:
67962306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_IP6DA;
68062306a36Sopenharmony_ci			break;
68162306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4SIP:
68262306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_L4SIP;
68362306a36Sopenharmony_ci			break;
68462306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4DIP:
68562306a36Sopenharmony_ci			field_id = MVPP22_CLS_FIELD_L4DIP;
68662306a36Sopenharmony_ci			break;
68762306a36Sopenharmony_ci		default:
68862306a36Sopenharmony_ci			return -EINVAL;
68962306a36Sopenharmony_ci		}
69062306a36Sopenharmony_ci		if (mvpp2_flow_add_hek_field(fe, field_id))
69162306a36Sopenharmony_ci			return -EINVAL;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/* Returns the size, in bits, of the corresponding HEK field */
69862306a36Sopenharmony_cistatic int mvpp2_cls_hek_field_size(u32 field)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	switch (field) {
70162306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_MAC_DA:
70262306a36Sopenharmony_ci		return 48;
70362306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_VLAN:
70462306a36Sopenharmony_ci		return 12;
70562306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_VLAN_PRI:
70662306a36Sopenharmony_ci		return 3;
70762306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP4SA:
70862306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP4DA:
70962306a36Sopenharmony_ci		return 32;
71062306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP6SA:
71162306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_IP6DA:
71262306a36Sopenharmony_ci		return 128;
71362306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_L4SIP:
71462306a36Sopenharmony_ci	case MVPP22_CLS_HEK_OPT_L4DIP:
71562306a36Sopenharmony_ci		return 16;
71662306a36Sopenharmony_ci	default:
71762306a36Sopenharmony_ci		return -1;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciconst struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	if (flow >= MVPP2_N_PRS_FLOWS)
72462306a36Sopenharmony_ci		return NULL;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	return &cls_flows[flow];
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/* Set the hash generation options for the given traffic flow.
73062306a36Sopenharmony_ci * One traffic flow (in the ethtool sense) has multiple classification flows,
73162306a36Sopenharmony_ci * to handle specific cases such as fragmentation, or the presence of a
73262306a36Sopenharmony_ci * VLAN / DSA Tag.
73362306a36Sopenharmony_ci *
73462306a36Sopenharmony_ci * Each of these individual flows has different constraints, for example we
73562306a36Sopenharmony_ci * can't hash fragmented packets on L4 data (else we would risk having packet
73662306a36Sopenharmony_ci * re-ordering), so each classification flows masks the options with their
73762306a36Sopenharmony_ci * supported ones.
73862306a36Sopenharmony_ci *
73962306a36Sopenharmony_ci */
74062306a36Sopenharmony_cistatic int mvpp2_port_rss_hash_opts_set(struct mvpp2_port *port, int flow_type,
74162306a36Sopenharmony_ci					u16 requested_opts)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
74462306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
74562306a36Sopenharmony_ci	int i, engine, flow_index;
74662306a36Sopenharmony_ci	u16 hash_opts;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	for_each_cls_flow_id_with_type(i, flow_type) {
74962306a36Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
75062306a36Sopenharmony_ci		if (!flow)
75162306a36Sopenharmony_ci			return -EINVAL;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, flow_index, &fe);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		hash_opts = flow->supported_hash_opts & requested_opts;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		/* Use C3HB engine to access L4 infos. This adds L4 infos to the
76062306a36Sopenharmony_ci		 * hash parameters
76162306a36Sopenharmony_ci		 */
76262306a36Sopenharmony_ci		if (hash_opts & MVPP22_CLS_HEK_L4_OPTS)
76362306a36Sopenharmony_ci			engine = MVPP22_CLS_ENGINE_C3HB;
76462306a36Sopenharmony_ci		else
76562306a36Sopenharmony_ci			engine = MVPP22_CLS_ENGINE_C3HA;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		if (mvpp2_flow_set_hek_fields(&fe, hash_opts))
76862306a36Sopenharmony_ci			return -EINVAL;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, engine);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		mvpp2_cls_flow_write(port->priv, &fe);
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ciu16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	u16 hash_opts = 0;
78162306a36Sopenharmony_ci	int n_fields, i, field;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	n_fields = mvpp2_cls_flow_hek_num_get(fe);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	for (i = 0; i < n_fields; i++) {
78662306a36Sopenharmony_ci		field = mvpp2_cls_flow_hek_get(fe, i);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		switch (field) {
78962306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_MAC_DA:
79062306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;
79162306a36Sopenharmony_ci			break;
79262306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_VLAN:
79362306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;
79462306a36Sopenharmony_ci			break;
79562306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_VLAN_PRI:
79662306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
79762306a36Sopenharmony_ci			break;
79862306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_L3_PROTO:
79962306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;
80062306a36Sopenharmony_ci			break;
80162306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_IP4SA:
80262306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP4SA;
80362306a36Sopenharmony_ci			break;
80462306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_IP4DA:
80562306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP4DA;
80662306a36Sopenharmony_ci			break;
80762306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_IP6SA:
80862306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP6SA;
80962306a36Sopenharmony_ci			break;
81062306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_IP6DA:
81162306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_IP6DA;
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_L4SIP:
81462306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;
81562306a36Sopenharmony_ci			break;
81662306a36Sopenharmony_ci		case MVPP22_CLS_FIELD_L4DIP:
81762306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;
81862306a36Sopenharmony_ci			break;
81962306a36Sopenharmony_ci		default:
82062306a36Sopenharmony_ci			break;
82162306a36Sopenharmony_ci		}
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci	return hash_opts;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/* Returns the hash opts for this flow. There are several classifier flows
82762306a36Sopenharmony_ci * for one traffic flow, this returns an aggregation of all configurations.
82862306a36Sopenharmony_ci */
82962306a36Sopenharmony_cistatic u16 mvpp2_port_rss_hash_opts_get(struct mvpp2_port *port, int flow_type)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
83262306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
83362306a36Sopenharmony_ci	int i, flow_index;
83462306a36Sopenharmony_ci	u16 hash_opts = 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	for_each_cls_flow_id_with_type(i, flow_type) {
83762306a36Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
83862306a36Sopenharmony_ci		if (!flow)
83962306a36Sopenharmony_ci			return 0;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, flow_index, &fe);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		hash_opts |= mvpp2_flow_get_hek_fields(&fe);
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return hash_opts;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic void mvpp2_cls_port_init_flows(struct mvpp2 *priv)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
85462306a36Sopenharmony_ci	int i;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
85762306a36Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
85862306a36Sopenharmony_ci		if (!flow)
85962306a36Sopenharmony_ci			break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		mvpp2_cls_flow_prs_init(priv, flow);
86262306a36Sopenharmony_ci		mvpp2_cls_flow_lkp_init(priv, flow);
86362306a36Sopenharmony_ci		mvpp2_cls_flow_init(priv, flow);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
87062306a36Sopenharmony_ci	u8 qh, ql, pmap;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	c2.index = MVPP22_CLS_C2_RSS_ENTRY(port->id);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	pmap = BIT(port->id);
87762306a36Sopenharmony_ci	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
87862306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* Match on Lookup Type */
88162306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
88262306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP22_CLS_LU_TYPE_ALL);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* Update RSS status after matching this entry */
88562306a36Sopenharmony_ci	c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Mark packet as "forwarded to software", needed for RSS */
88862306a36Sopenharmony_ci	c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* Configure the default rx queue : Update Queue Low and Queue High, but
89162306a36Sopenharmony_ci	 * don't lock, since the rx queue selection might be overridden by RSS
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD) |
89462306a36Sopenharmony_ci		   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
89762306a36Sopenharmony_ci	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
90062306a36Sopenharmony_ci		      MVPP22_CLS_C2_ATTR0_QLOW(ql);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	c2.valid = true;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci/* Classifier default initialization */
90862306a36Sopenharmony_civoid mvpp2_cls_init(struct mvpp2 *priv)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
91162306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
91262306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
91362306a36Sopenharmony_ci	int index;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* Enable classifier */
91662306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	/* Clear classifier flow table */
91962306a36Sopenharmony_ci	memset(&fe.data, 0, sizeof(fe.data));
92062306a36Sopenharmony_ci	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
92162306a36Sopenharmony_ci		fe.index = index;
92262306a36Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Clear classifier lookup table */
92662306a36Sopenharmony_ci	le.data = 0;
92762306a36Sopenharmony_ci	for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) {
92862306a36Sopenharmony_ci		le.lkpid = index;
92962306a36Sopenharmony_ci		le.way = 0;
93062306a36Sopenharmony_ci		mvpp2_cls_lookup_write(priv, &le);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		le.way = 1;
93362306a36Sopenharmony_ci		mvpp2_cls_lookup_write(priv, &le);
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	/* Clear C2 TCAM engine table */
93762306a36Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
93862306a36Sopenharmony_ci	c2.valid = false;
93962306a36Sopenharmony_ci	for (index = 0; index < MVPP22_CLS_C2_N_ENTRIES; index++) {
94062306a36Sopenharmony_ci		c2.index = index;
94162306a36Sopenharmony_ci		mvpp2_cls_c2_write(priv, &c2);
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* Disable the FIFO stages in C2 engine, which are only used in BIST
94562306a36Sopenharmony_ci	 * mode
94662306a36Sopenharmony_ci	 */
94762306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_CTRL,
94862306a36Sopenharmony_ci		    MVPP22_CLS_C2_TCAM_BYPASS_FIFO);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	mvpp2_cls_port_init_flows(priv);
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_civoid mvpp2_cls_port_config(struct mvpp2_port *port)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct mvpp2_cls_lookup_entry le;
95662306a36Sopenharmony_ci	u32 val;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* Set way for the port */
95962306a36Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG);
96062306a36Sopenharmony_ci	val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id);
96162306a36Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* Pick the entry to be accessed in lookup ID decoding table
96462306a36Sopenharmony_ci	 * according to the way and lkpid.
96562306a36Sopenharmony_ci	 */
96662306a36Sopenharmony_ci	le.lkpid = port->id;
96762306a36Sopenharmony_ci	le.way = 0;
96862306a36Sopenharmony_ci	le.data = 0;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/* Set initial CPU queue for receiving packets */
97162306a36Sopenharmony_ci	le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
97262306a36Sopenharmony_ci	le.data |= port->first_rxq;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/* Disable classification engines */
97562306a36Sopenharmony_ci	le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* Update lookup ID table entry */
97862306a36Sopenharmony_ci	mvpp2_cls_lookup_write(port->priv, &le);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	mvpp2_port_c2_cls_init(port);
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ciu32 mvpp2_cls_c2_hit_count(struct mvpp2 *priv, int c2_index)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2_index);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	return mvpp2_read(priv, MVPP22_CLS_C2_HIT_CTR);
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic void mvpp2_rss_port_c2_enable(struct mvpp2_port *port, u32 ctx)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
99362306a36Sopenharmony_ci	u8 qh, ql;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* The RxQ number is used to select the RSS table. It that case, we set
99862306a36Sopenharmony_ci	 * it to be the ctx number.
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
100162306a36Sopenharmony_ci	ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
100462306a36Sopenharmony_ci		     MVPP22_CLS_C2_ATTR0_QLOW(ql);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic void mvpp2_rss_port_c2_disable(struct mvpp2_port *port)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
101462306a36Sopenharmony_ci	u8 qh, ql;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Reset the default destination RxQ to the port's first rx queue. */
101962306a36Sopenharmony_ci	qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
102062306a36Sopenharmony_ci	ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
102362306a36Sopenharmony_ci		      MVPP22_CLS_C2_ATTR0_QLOW(ql);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	c2.attr[2] &= ~MVPP22_CLS_C2_ATTR2_RSS_EN;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic inline int mvpp22_rss_ctx(struct mvpp2_port *port, int port_rss_ctx)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	return port->rss_ctx[port_rss_ctx];
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ciint mvpp22_port_rss_enable(struct mvpp2_port *port)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	if (mvpp22_rss_ctx(port, 0) < 0)
103862306a36Sopenharmony_ci		return -EINVAL;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	mvpp2_rss_port_c2_enable(port, mvpp22_rss_ctx(port, 0));
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return 0;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ciint mvpp22_port_rss_disable(struct mvpp2_port *port)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	if (mvpp22_rss_ctx(port, 0) < 0)
104862306a36Sopenharmony_ci		return -EINVAL;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	mvpp2_rss_port_c2_disable(port);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	return 0;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic void mvpp22_port_c2_lookup_disable(struct mvpp2_port *port, int entry)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	mvpp2_cls_c2_read(port->priv, entry, &c2);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	/* Clear the port map so that the entry doesn't match anymore */
106262306a36Sopenharmony_ci	c2.tcam[4] &= ~(MVPP22_CLS_C2_PORT_ID(BIT(port->id)));
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci/* Set CPU queue number for oversize packets */
106862306a36Sopenharmony_civoid mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	u32 val;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id),
107362306a36Sopenharmony_ci		    port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id),
107662306a36Sopenharmony_ci		    (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS));
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG);
107962306a36Sopenharmony_ci	val &= ~MVPP2_CLS_SWFWD_PCTRL_MASK(port->id);
108062306a36Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
108462306a36Sopenharmony_ci				       struct mvpp2_rfs_rule *rule)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct flow_action_entry *act;
108762306a36Sopenharmony_ci	struct mvpp2_cls_c2_entry c2;
108862306a36Sopenharmony_ci	u8 qh, ql, pmap;
108962306a36Sopenharmony_ci	int index, ctx;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))
109262306a36Sopenharmony_ci		return -EOPNOTSUPP;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	memset(&c2, 0, sizeof(c2));
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	index = mvpp2_cls_c2_port_flow_index(port, rule->loc);
109762306a36Sopenharmony_ci	if (index < 0)
109862306a36Sopenharmony_ci		return -EINVAL;
109962306a36Sopenharmony_ci	c2.index = index;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	act = &rule->flow->action.entries[0];
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	rule->c2_index = c2.index;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	c2.tcam[3] = (rule->c2_tcam & 0xffff) |
110662306a36Sopenharmony_ci		     ((rule->c2_tcam_mask & 0xffff) << 16);
110762306a36Sopenharmony_ci	c2.tcam[2] = ((rule->c2_tcam >> 16) & 0xffff) |
110862306a36Sopenharmony_ci		     (((rule->c2_tcam_mask >> 16) & 0xffff) << 16);
110962306a36Sopenharmony_ci	c2.tcam[1] = ((rule->c2_tcam >> 32) & 0xffff) |
111062306a36Sopenharmony_ci		     (((rule->c2_tcam_mask >> 32) & 0xffff) << 16);
111162306a36Sopenharmony_ci	c2.tcam[0] = ((rule->c2_tcam >> 48) & 0xffff) |
111262306a36Sopenharmony_ci		     (((rule->c2_tcam_mask >> 48) & 0xffff) << 16);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	pmap = BIT(port->id);
111562306a36Sopenharmony_ci	c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
111662306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* Match on Lookup Type */
111962306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
112062306a36Sopenharmony_ci	c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(rule->loc);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (act->id == FLOW_ACTION_DROP) {
112362306a36Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_RED_LOCK);
112462306a36Sopenharmony_ci	} else {
112562306a36Sopenharmony_ci		/* We want to keep the default color derived from the Header
112662306a36Sopenharmony_ci		 * Parser drop entries, for VLAN and MAC filtering. This will
112762306a36Sopenharmony_ci		 * assign a default color of Green or Red, and we want matches
112862306a36Sopenharmony_ci		 * with a non-drop action to keep that color.
112962306a36Sopenharmony_ci		 */
113062306a36Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_NO_UPD_LOCK);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		/* Update RSS status after matching this entry */
113362306a36Sopenharmony_ci		if (act->queue.ctx)
113462306a36Sopenharmony_ci			c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		/* Always lock the RSS_EN decision. We might have high prio
113762306a36Sopenharmony_ci		 * rules steering to an RXQ, and a lower one steering to RSS,
113862306a36Sopenharmony_ci		 * we don't want the low prio RSS rule overwriting this flag.
113962306a36Sopenharmony_ci		 */
114062306a36Sopenharmony_ci		c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		/* Mark packet as "forwarded to software", needed for RSS */
114362306a36Sopenharmony_ci		c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD_LOCK) |
114662306a36Sopenharmony_ci			   MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD_LOCK);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		if (act->queue.ctx) {
114962306a36Sopenharmony_ci			/* Get the global ctx number */
115062306a36Sopenharmony_ci			ctx = mvpp22_rss_ctx(port, act->queue.ctx);
115162306a36Sopenharmony_ci			if (ctx < 0)
115262306a36Sopenharmony_ci				return -EINVAL;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci			qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
115562306a36Sopenharmony_ci			ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
115662306a36Sopenharmony_ci		} else {
115762306a36Sopenharmony_ci			qh = ((act->queue.index + port->first_rxq) >> 3) &
115862306a36Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
115962306a36Sopenharmony_ci			ql = (act->queue.index + port->first_rxq) &
116062306a36Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QLOW_MASK;
116162306a36Sopenharmony_ci		}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
116462306a36Sopenharmony_ci			      MVPP22_CLS_C2_ATTR0_QLOW(ql);
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	c2.valid = true;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	mvpp2_cls_c2_write(port->priv, &c2);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	return 0;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_cistatic int mvpp2_port_c2_rfs_rule_insert(struct mvpp2_port *port,
117562306a36Sopenharmony_ci					 struct mvpp2_rfs_rule *rule)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	return mvpp2_port_c2_tcam_rule_add(port, rule);
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic int mvpp2_port_cls_rfs_rule_remove(struct mvpp2_port *port,
118162306a36Sopenharmony_ci					  struct mvpp2_rfs_rule *rule)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
118462306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
118562306a36Sopenharmony_ci	int index, i;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	for_each_cls_flow_id_containing_type(i, rule->flow_type) {
118862306a36Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
118962306a36Sopenharmony_ci		if (!flow)
119062306a36Sopenharmony_ci			return 0;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		mvpp2_cls_flow_read(port->priv, index, &fe);
119562306a36Sopenharmony_ci		mvpp2_cls_flow_port_remove(&fe, BIT(port->id));
119662306a36Sopenharmony_ci		mvpp2_cls_flow_write(port->priv, &fe);
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (rule->c2_index >= 0)
120062306a36Sopenharmony_ci		mvpp22_port_c2_lookup_disable(port, rule->c2_index);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	return 0;
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port,
120662306a36Sopenharmony_ci					  struct mvpp2_rfs_rule *rule)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	const struct mvpp2_cls_flow *flow;
120962306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
121062306a36Sopenharmony_ci	struct mvpp2_cls_flow_entry fe;
121162306a36Sopenharmony_ci	int index, ret, i;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (rule->engine != MVPP22_CLS_ENGINE_C2)
121462306a36Sopenharmony_ci		return -EOPNOTSUPP;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	ret = mvpp2_port_c2_rfs_rule_insert(port, rule);
121762306a36Sopenharmony_ci	if (ret)
121862306a36Sopenharmony_ci		return ret;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	for_each_cls_flow_id_containing_type(i, rule->flow_type) {
122162306a36Sopenharmony_ci		flow = mvpp2_cls_flow_get(i);
122262306a36Sopenharmony_ci		if (!flow)
122362306a36Sopenharmony_ci			return 0;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		if ((rule->hek_fields & flow->supported_hash_opts) != rule->hek_fields)
122662306a36Sopenharmony_ci			continue;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		mvpp2_cls_flow_read(priv, index, &fe);
123162306a36Sopenharmony_ci		mvpp2_cls_flow_eng_set(&fe, rule->engine);
123262306a36Sopenharmony_ci		mvpp2_cls_flow_port_id_sel(&fe, true);
123362306a36Sopenharmony_ci		mvpp2_flow_set_hek_fields(&fe, rule->hek_fields);
123462306a36Sopenharmony_ci		mvpp2_cls_flow_lu_type_set(&fe, rule->loc);
123562306a36Sopenharmony_ci		mvpp2_cls_flow_port_add(&fe, 0xf);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci		mvpp2_cls_flow_write(priv, &fe);
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	return 0;
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct flow_rule *flow = rule->flow;
124662306a36Sopenharmony_ci	int offs = 0;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* The order of insertion in C2 tcam must match the order in which
124962306a36Sopenharmony_ci	 * the fields are found in the header
125062306a36Sopenharmony_ci	 */
125162306a36Sopenharmony_ci	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_VLAN)) {
125262306a36Sopenharmony_ci		struct flow_match_vlan match;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci		flow_rule_match_vlan(flow, &match);
125562306a36Sopenharmony_ci		if (match.mask->vlan_id) {
125662306a36Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci			rule->c2_tcam |= ((u64)match.key->vlan_id) << offs;
125962306a36Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)match.mask->vlan_id) << offs;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci			/* Don't update the offset yet */
126262306a36Sopenharmony_ci		}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		if (match.mask->vlan_priority) {
126562306a36Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci			/* VLAN pri is always at offset 13 relative to the
126862306a36Sopenharmony_ci			 * current offset
126962306a36Sopenharmony_ci			 */
127062306a36Sopenharmony_ci			rule->c2_tcam |= ((u64)match.key->vlan_priority) <<
127162306a36Sopenharmony_ci				(offs + 13);
127262306a36Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)match.mask->vlan_priority) <<
127362306a36Sopenharmony_ci				(offs + 13);
127462306a36Sopenharmony_ci		}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		if (match.mask->vlan_dei)
127762306a36Sopenharmony_ci			return -EOPNOTSUPP;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci		/* vlan id and prio always seem to take a full 16-bit slot in
128062306a36Sopenharmony_ci		 * the Header Extracted Key.
128162306a36Sopenharmony_ci		 */
128262306a36Sopenharmony_ci		offs += 16;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) {
128662306a36Sopenharmony_ci		struct flow_match_ports match;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci		flow_rule_match_ports(flow, &match);
128962306a36Sopenharmony_ci		if (match.mask->src) {
129062306a36Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4SIP;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci			rule->c2_tcam |= ((u64)ntohs(match.key->src)) << offs;
129362306a36Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->src)) << offs;
129462306a36Sopenharmony_ci			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP);
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		if (match.mask->dst) {
129862306a36Sopenharmony_ci			rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4DIP;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci			rule->c2_tcam |= ((u64)ntohs(match.key->dst)) << offs;
130162306a36Sopenharmony_ci			rule->c2_tcam_mask |= ((u64)ntohs(match.mask->dst)) << offs;
130262306a36Sopenharmony_ci			offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP);
130362306a36Sopenharmony_ci		}
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (hweight16(rule->hek_fields) > MVPP2_FLOW_N_FIELDS)
130762306a36Sopenharmony_ci		return -EOPNOTSUPP;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	struct flow_rule *flow = rule->flow;
131562306a36Sopenharmony_ci	struct flow_action_entry *act;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (!flow_action_basic_hw_stats_check(&rule->flow->action, NULL))
131862306a36Sopenharmony_ci		return -EOPNOTSUPP;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	act = &flow->action.entries[0];
132162306a36Sopenharmony_ci	if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
132262306a36Sopenharmony_ci		return -EOPNOTSUPP;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	/* When both an RSS context and an queue index are set, the index
132562306a36Sopenharmony_ci	 * is considered as an offset to be added to the indirection table
132662306a36Sopenharmony_ci	 * entries. We don't support this, so reject this rule.
132762306a36Sopenharmony_ci	 */
132862306a36Sopenharmony_ci	if (act->queue.ctx && act->queue.index)
132962306a36Sopenharmony_ci		return -EOPNOTSUPP;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	/* For now, only use the C2 engine which has a HEK size limited to 64
133262306a36Sopenharmony_ci	 * bits for TCAM matching.
133362306a36Sopenharmony_ci	 */
133462306a36Sopenharmony_ci	rule->engine = MVPP22_CLS_ENGINE_C2;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (mvpp2_cls_c2_build_match(rule))
133762306a36Sopenharmony_ci		return -EINVAL;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	return 0;
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ciint mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port,
134362306a36Sopenharmony_ci			       struct ethtool_rxnfc *rxnfc)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	struct mvpp2_ethtool_fs *efs;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (rxnfc->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
134862306a36Sopenharmony_ci		return -EINVAL;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	efs = port->rfs_rules[rxnfc->fs.location];
135162306a36Sopenharmony_ci	if (!efs)
135262306a36Sopenharmony_ci		return -ENOENT;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	memcpy(rxnfc, &efs->rxnfc, sizeof(efs->rxnfc));
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return 0;
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ciint mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
136062306a36Sopenharmony_ci			       struct ethtool_rxnfc *info)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	struct ethtool_rx_flow_spec_input input = {};
136362306a36Sopenharmony_ci	struct ethtool_rx_flow_rule *ethtool_rule;
136462306a36Sopenharmony_ci	struct mvpp2_ethtool_fs *efs, *old_efs;
136562306a36Sopenharmony_ci	int ret = 0;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
136862306a36Sopenharmony_ci		return -EINVAL;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	efs = kzalloc(sizeof(*efs), GFP_KERNEL);
137162306a36Sopenharmony_ci	if (!efs)
137262306a36Sopenharmony_ci		return -ENOMEM;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	input.fs = &info->fs;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* We need to manually set the rss_ctx, since this info isn't present
137762306a36Sopenharmony_ci	 * in info->fs
137862306a36Sopenharmony_ci	 */
137962306a36Sopenharmony_ci	if (info->fs.flow_type & FLOW_RSS)
138062306a36Sopenharmony_ci		input.rss_ctx = info->rss_context;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	ethtool_rule = ethtool_rx_flow_rule_create(&input);
138362306a36Sopenharmony_ci	if (IS_ERR(ethtool_rule)) {
138462306a36Sopenharmony_ci		ret = PTR_ERR(ethtool_rule);
138562306a36Sopenharmony_ci		goto clean_rule;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	efs->rule.flow = ethtool_rule->rule;
138962306a36Sopenharmony_ci	efs->rule.flow_type = mvpp2_cls_ethtool_flow_to_type(info->fs.flow_type);
139062306a36Sopenharmony_ci	if (efs->rule.flow_type < 0) {
139162306a36Sopenharmony_ci		ret = efs->rule.flow_type;
139262306a36Sopenharmony_ci		goto clean_rule;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ret = mvpp2_cls_rfs_parse_rule(&efs->rule);
139662306a36Sopenharmony_ci	if (ret)
139762306a36Sopenharmony_ci		goto clean_eth_rule;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	efs->rule.loc = info->fs.location;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	/* Replace an already existing rule */
140262306a36Sopenharmony_ci	if (port->rfs_rules[efs->rule.loc]) {
140362306a36Sopenharmony_ci		old_efs = port->rfs_rules[efs->rule.loc];
140462306a36Sopenharmony_ci		ret = mvpp2_port_cls_rfs_rule_remove(port, &old_efs->rule);
140562306a36Sopenharmony_ci		if (ret)
140662306a36Sopenharmony_ci			goto clean_eth_rule;
140762306a36Sopenharmony_ci		kfree(old_efs);
140862306a36Sopenharmony_ci		port->n_rfs_rules--;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	ret = mvpp2_port_flt_rfs_rule_insert(port, &efs->rule);
141262306a36Sopenharmony_ci	if (ret)
141362306a36Sopenharmony_ci		goto clean_eth_rule;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	ethtool_rx_flow_rule_destroy(ethtool_rule);
141662306a36Sopenharmony_ci	efs->rule.flow = NULL;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	memcpy(&efs->rxnfc, info, sizeof(*info));
141962306a36Sopenharmony_ci	port->rfs_rules[efs->rule.loc] = efs;
142062306a36Sopenharmony_ci	port->n_rfs_rules++;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	return ret;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ciclean_eth_rule:
142562306a36Sopenharmony_ci	ethtool_rx_flow_rule_destroy(ethtool_rule);
142662306a36Sopenharmony_ciclean_rule:
142762306a36Sopenharmony_ci	kfree(efs);
142862306a36Sopenharmony_ci	return ret;
142962306a36Sopenharmony_ci}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ciint mvpp2_ethtool_cls_rule_del(struct mvpp2_port *port,
143262306a36Sopenharmony_ci			       struct ethtool_rxnfc *info)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	struct mvpp2_ethtool_fs *efs;
143562306a36Sopenharmony_ci	int ret;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
143862306a36Sopenharmony_ci		return -EINVAL;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	efs = port->rfs_rules[info->fs.location];
144162306a36Sopenharmony_ci	if (!efs)
144262306a36Sopenharmony_ci		return -EINVAL;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/* Remove the rule from the engines. */
144562306a36Sopenharmony_ci	ret = mvpp2_port_cls_rfs_rule_remove(port, &efs->rule);
144662306a36Sopenharmony_ci	if (ret)
144762306a36Sopenharmony_ci		return ret;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	port->n_rfs_rules--;
145062306a36Sopenharmony_ci	port->rfs_rules[info->fs.location] = NULL;
145162306a36Sopenharmony_ci	kfree(efs);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	return 0;
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_cistatic inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	int nrxqs, cpu, cpus = num_possible_cpus();
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* Number of RXQs per CPU */
146162306a36Sopenharmony_ci	nrxqs = port->nrxqs / cpus;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* CPU that will handle this rx queue */
146462306a36Sopenharmony_ci	cpu = rxq / nrxqs;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (!cpu_online(cpu))
146762306a36Sopenharmony_ci		return port->first_rxq;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	/* Indirection to better distribute the paquets on the CPUs when
147062306a36Sopenharmony_ci	 * configuring the RSS queues.
147162306a36Sopenharmony_ci	 */
147262306a36Sopenharmony_ci	return port->first_rxq + ((rxq * nrxqs + rxq / cpus) % port->nrxqs);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic void mvpp22_rss_fill_table(struct mvpp2_port *port,
147662306a36Sopenharmony_ci				  struct mvpp2_rss_table *table,
147762306a36Sopenharmony_ci				  u32 rss_ctx)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
148062306a36Sopenharmony_ci	int i;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {
148362306a36Sopenharmony_ci		u32 sel = MVPP22_RSS_INDEX_TABLE(rss_ctx) |
148462306a36Sopenharmony_ci			  MVPP22_RSS_INDEX_TABLE_ENTRY(i);
148562306a36Sopenharmony_ci		mvpp2_write(priv, MVPP22_RSS_INDEX, sel);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY,
148862306a36Sopenharmony_ci			    mvpp22_rxfh_indir(port, table->indir[i]));
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_cistatic int mvpp22_rss_context_create(struct mvpp2_port *port, u32 *rss_ctx)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
149562306a36Sopenharmony_ci	u32 ctx;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	/* Find the first free RSS table */
149862306a36Sopenharmony_ci	for (ctx = 0; ctx < MVPP22_N_RSS_TABLES; ctx++) {
149962306a36Sopenharmony_ci		if (!priv->rss_tables[ctx])
150062306a36Sopenharmony_ci			break;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	if (ctx == MVPP22_N_RSS_TABLES)
150462306a36Sopenharmony_ci		return -EINVAL;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	priv->rss_tables[ctx] = kzalloc(sizeof(*priv->rss_tables[ctx]),
150762306a36Sopenharmony_ci					GFP_KERNEL);
150862306a36Sopenharmony_ci	if (!priv->rss_tables[ctx])
150962306a36Sopenharmony_ci		return -ENOMEM;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	*rss_ctx = ctx;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* Set the table width: replace the whole classifier Rx queue number
151462306a36Sopenharmony_ci	 * with the ones configured in RSS table entries.
151562306a36Sopenharmony_ci	 */
151662306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(ctx));
151762306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(ctx));
152062306a36Sopenharmony_ci	mvpp2_write(priv, MVPP22_RXQ2RSS_TABLE, MVPP22_RSS_TABLE_POINTER(ctx));
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return 0;
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ciint mvpp22_port_rss_ctx_create(struct mvpp2_port *port, u32 *port_ctx)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	u32 rss_ctx;
152862306a36Sopenharmony_ci	int ret, i;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	ret = mvpp22_rss_context_create(port, &rss_ctx);
153162306a36Sopenharmony_ci	if (ret)
153262306a36Sopenharmony_ci		return ret;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	/* Find the first available context number in the port, starting from 1.
153562306a36Sopenharmony_ci	 * Context 0 on each port is reserved for the default context.
153662306a36Sopenharmony_ci	 */
153762306a36Sopenharmony_ci	for (i = 1; i < MVPP22_N_RSS_TABLES; i++) {
153862306a36Sopenharmony_ci		if (port->rss_ctx[i] < 0)
153962306a36Sopenharmony_ci			break;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (i == MVPP22_N_RSS_TABLES)
154362306a36Sopenharmony_ci		return -EINVAL;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	port->rss_ctx[i] = rss_ctx;
154662306a36Sopenharmony_ci	*port_ctx = i;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	return 0;
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic struct mvpp2_rss_table *mvpp22_rss_table_get(struct mvpp2 *priv,
155262306a36Sopenharmony_ci						    int rss_ctx)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
155562306a36Sopenharmony_ci		return NULL;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	return priv->rss_tables[rss_ctx];
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ciint mvpp22_port_rss_ctx_delete(struct mvpp2_port *port, u32 port_ctx)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
156362306a36Sopenharmony_ci	struct ethtool_rxnfc *rxnfc;
156462306a36Sopenharmony_ci	int i, rss_ctx, ret;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	rss_ctx = mvpp22_rss_ctx(port, port_ctx);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
156962306a36Sopenharmony_ci		return -EINVAL;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	/* Invalidate any active classification rule that use this context */
157262306a36Sopenharmony_ci	for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
157362306a36Sopenharmony_ci		if (!port->rfs_rules[i])
157462306a36Sopenharmony_ci			continue;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		rxnfc = &port->rfs_rules[i]->rxnfc;
157762306a36Sopenharmony_ci		if (!(rxnfc->fs.flow_type & FLOW_RSS) ||
157862306a36Sopenharmony_ci		    rxnfc->rss_context != port_ctx)
157962306a36Sopenharmony_ci			continue;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci		ret = mvpp2_ethtool_cls_rule_del(port, rxnfc);
158262306a36Sopenharmony_ci		if (ret) {
158362306a36Sopenharmony_ci			netdev_warn(port->dev,
158462306a36Sopenharmony_ci				    "couldn't remove classification rule %d associated to this context",
158562306a36Sopenharmony_ci				    rxnfc->fs.location);
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	kfree(priv->rss_tables[rss_ctx]);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	priv->rss_tables[rss_ctx] = NULL;
159262306a36Sopenharmony_ci	port->rss_ctx[port_ctx] = -1;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	return 0;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ciint mvpp22_port_rss_ctx_indir_set(struct mvpp2_port *port, u32 port_ctx,
159862306a36Sopenharmony_ci				  const u32 *indir)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	int rss_ctx = mvpp22_rss_ctx(port, port_ctx);
160162306a36Sopenharmony_ci	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
160262306a36Sopenharmony_ci								 rss_ctx);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (!rss_table)
160562306a36Sopenharmony_ci		return -EINVAL;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	memcpy(rss_table->indir, indir,
160862306a36Sopenharmony_ci	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	mvpp22_rss_fill_table(port, rss_table, rss_ctx);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	return 0;
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ciint mvpp22_port_rss_ctx_indir_get(struct mvpp2_port *port, u32 port_ctx,
161662306a36Sopenharmony_ci				  u32 *indir)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	int rss_ctx =  mvpp22_rss_ctx(port, port_ctx);
161962306a36Sopenharmony_ci	struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
162062306a36Sopenharmony_ci								 rss_ctx);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	if (!rss_table)
162362306a36Sopenharmony_ci		return -EINVAL;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	memcpy(indir, rss_table->indir,
162662306a36Sopenharmony_ci	       MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return 0;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ciint mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	u16 hash_opts = 0;
163462306a36Sopenharmony_ci	u32 flow_type;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	switch (flow_type) {
163962306a36Sopenharmony_ci	case MVPP22_FLOW_TCP4:
164062306a36Sopenharmony_ci	case MVPP22_FLOW_UDP4:
164162306a36Sopenharmony_ci	case MVPP22_FLOW_TCP6:
164262306a36Sopenharmony_ci	case MVPP22_FLOW_UDP6:
164362306a36Sopenharmony_ci		if (info->data & RXH_L4_B_0_1)
164462306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4SIP;
164562306a36Sopenharmony_ci		if (info->data & RXH_L4_B_2_3)
164662306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L4DIP;
164762306a36Sopenharmony_ci		fallthrough;
164862306a36Sopenharmony_ci	case MVPP22_FLOW_IP4:
164962306a36Sopenharmony_ci	case MVPP22_FLOW_IP6:
165062306a36Sopenharmony_ci		if (info->data & RXH_L2DA)
165162306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_MAC_DA;
165262306a36Sopenharmony_ci		if (info->data & RXH_VLAN)
165362306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;
165462306a36Sopenharmony_ci		if (info->data & RXH_L3_PROTO)
165562306a36Sopenharmony_ci			hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;
165662306a36Sopenharmony_ci		if (info->data & RXH_IP_SRC)
165762306a36Sopenharmony_ci			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4SA |
165862306a36Sopenharmony_ci				     MVPP22_CLS_HEK_OPT_IP6SA);
165962306a36Sopenharmony_ci		if (info->data & RXH_IP_DST)
166062306a36Sopenharmony_ci			hash_opts |= (MVPP22_CLS_HEK_OPT_IP4DA |
166162306a36Sopenharmony_ci				     MVPP22_CLS_HEK_OPT_IP6DA);
166262306a36Sopenharmony_ci		break;
166362306a36Sopenharmony_ci	default: return -EOPNOTSUPP;
166462306a36Sopenharmony_ci	}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	return mvpp2_port_rss_hash_opts_set(port, flow_type, hash_opts);
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ciint mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	unsigned long hash_opts;
167262306a36Sopenharmony_ci	u32 flow_type;
167362306a36Sopenharmony_ci	int i;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	flow_type = mvpp2_cls_ethtool_flow_to_type(info->flow_type);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	hash_opts = mvpp2_port_rss_hash_opts_get(port, flow_type);
167862306a36Sopenharmony_ci	info->data = 0;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {
168162306a36Sopenharmony_ci		switch (BIT(i)) {
168262306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_MAC_DA:
168362306a36Sopenharmony_ci			info->data |= RXH_L2DA;
168462306a36Sopenharmony_ci			break;
168562306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_VLAN:
168662306a36Sopenharmony_ci			info->data |= RXH_VLAN;
168762306a36Sopenharmony_ci			break;
168862306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L3_PROTO:
168962306a36Sopenharmony_ci			info->data |= RXH_L3_PROTO;
169062306a36Sopenharmony_ci			break;
169162306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4SA:
169262306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6SA:
169362306a36Sopenharmony_ci			info->data |= RXH_IP_SRC;
169462306a36Sopenharmony_ci			break;
169562306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP4DA:
169662306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_IP6DA:
169762306a36Sopenharmony_ci			info->data |= RXH_IP_DST;
169862306a36Sopenharmony_ci			break;
169962306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4SIP:
170062306a36Sopenharmony_ci			info->data |= RXH_L4_B_0_1;
170162306a36Sopenharmony_ci			break;
170262306a36Sopenharmony_ci		case MVPP22_CLS_HEK_OPT_L4DIP:
170362306a36Sopenharmony_ci			info->data |= RXH_L4_B_2_3;
170462306a36Sopenharmony_ci			break;
170562306a36Sopenharmony_ci		default:
170662306a36Sopenharmony_ci			return -EINVAL;
170762306a36Sopenharmony_ci		}
170862306a36Sopenharmony_ci	}
170962306a36Sopenharmony_ci	return 0;
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ciint mvpp22_port_rss_init(struct mvpp2_port *port)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct mvpp2_rss_table *table;
171562306a36Sopenharmony_ci	u32 context = 0;
171662306a36Sopenharmony_ci	int i, ret;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	for (i = 0; i < MVPP22_N_RSS_TABLES; i++)
171962306a36Sopenharmony_ci		port->rss_ctx[i] = -1;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	ret = mvpp22_rss_context_create(port, &context);
172262306a36Sopenharmony_ci	if (ret)
172362306a36Sopenharmony_ci		return ret;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	table = mvpp22_rss_table_get(port->priv, context);
172662306a36Sopenharmony_ci	if (!table)
172762306a36Sopenharmony_ci		return -EINVAL;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	port->rss_ctx[0] = context;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* Configure the first table to evenly distribute the packets across
173262306a36Sopenharmony_ci	 * real Rx Queues. The table entries map a hash to a port Rx Queue.
173362306a36Sopenharmony_ci	 */
173462306a36Sopenharmony_ci	for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++)
173562306a36Sopenharmony_ci		table->indir[i] = ethtool_rxfh_indir_default(i, port->nrxqs);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	mvpp22_rss_fill_table(port, table, mvpp22_rss_ctx(port, 0));
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Configure default flows */
174062306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP4, MVPP22_CLS_HEK_IP4_2T);
174162306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP6, MVPP22_CLS_HEK_IP6_2T);
174262306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP4, MVPP22_CLS_HEK_IP4_5T);
174362306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP6, MVPP22_CLS_HEK_IP6_5T);
174462306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP4, MVPP22_CLS_HEK_IP4_5T);
174562306a36Sopenharmony_ci	mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP6, MVPP22_CLS_HEK_IP6_5T);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	return 0;
174862306a36Sopenharmony_ci}
1749