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