12ae7408fSSathya Perla /* Broadcom NetXtreme-C/E network driver.
22ae7408fSSathya Perla *
32ae7408fSSathya Perla * Copyright (c) 2017 Broadcom Limited
42ae7408fSSathya Perla *
52ae7408fSSathya Perla * This program is free software; you can redistribute it and/or modify
62ae7408fSSathya Perla * it under the terms of the GNU General Public License as published by
72ae7408fSSathya Perla * the Free Software Foundation.
82ae7408fSSathya Perla */
92ae7408fSSathya Perla
102ae7408fSSathya Perla #include <linux/netdevice.h>
112ae7408fSSathya Perla #include <linux/inetdevice.h>
122ae7408fSSathya Perla #include <linux/if_vlan.h>
132ae7408fSSathya Perla #include <net/flow_dissector.h>
142ae7408fSSathya Perla #include <net/pkt_cls.h>
152ae7408fSSathya Perla #include <net/tc_act/tc_gact.h>
162ae7408fSSathya Perla #include <net/tc_act/tc_skbedit.h>
172ae7408fSSathya Perla #include <net/tc_act/tc_mirred.h>
182ae7408fSSathya Perla #include <net/tc_act/tc_vlan.h>
1990f90624SVenkat Duvvuru #include <net/tc_act/tc_pedit.h>
208c95f773SSathya Perla #include <net/tc_act/tc_tunnel_key.h>
21627c89d0SSriharsha Basavapatna #include <net/vxlan.h>
222ae7408fSSathya Perla
232ae7408fSSathya Perla #include "bnxt_hsi.h"
242ae7408fSSathya Perla #include "bnxt.h"
253c8c20dbSEdwin Peer #include "bnxt_hwrm.h"
262ae7408fSSathya Perla #include "bnxt_sriov.h"
272ae7408fSSathya Perla #include "bnxt_tc.h"
282ae7408fSSathya Perla #include "bnxt_vfr.h"
292ae7408fSSathya Perla
302ae7408fSSathya Perla #define BNXT_FID_INVALID 0xffff
312ae7408fSSathya Perla #define VLAN_TCI(vid, prio) ((vid) | ((prio) << VLAN_PRIO_SHIFT))
322ae7408fSSathya Perla
33e32d4e60SVenkat Duvvuru #define is_vlan_pcp_wildcarded(vlan_tci_mask) \
34e32d4e60SVenkat Duvvuru ((ntohs(vlan_tci_mask) & VLAN_PRIO_MASK) == 0x0000)
35e32d4e60SVenkat Duvvuru #define is_vlan_pcp_exactmatch(vlan_tci_mask) \
36e32d4e60SVenkat Duvvuru ((ntohs(vlan_tci_mask) & VLAN_PRIO_MASK) == VLAN_PRIO_MASK)
37e32d4e60SVenkat Duvvuru #define is_vlan_pcp_zero(vlan_tci) \
38e32d4e60SVenkat Duvvuru ((ntohs(vlan_tci) & VLAN_PRIO_MASK) == 0x0000)
39e32d4e60SVenkat Duvvuru #define is_vid_exactmatch(vlan_tci_mask) \
40e32d4e60SVenkat Duvvuru ((ntohs(vlan_tci_mask) & VLAN_VID_MASK) == VLAN_VID_MASK)
41e32d4e60SVenkat Duvvuru
4290f90624SVenkat Duvvuru static bool is_wildcard(void *mask, int len);
4390f90624SVenkat Duvvuru static bool is_exactmatch(void *mask, int len);
442ae7408fSSathya Perla /* Return the dst fid of the func for flow forwarding
452ae7408fSSathya Perla * For PFs: src_fid is the fid of the PF
462ae7408fSSathya Perla * For VF-reps: src_fid the fid of the VF
472ae7408fSSathya Perla */
bnxt_flow_get_dst_fid(struct bnxt * pf_bp,struct net_device * dev)482ae7408fSSathya Perla static u16 bnxt_flow_get_dst_fid(struct bnxt *pf_bp, struct net_device *dev)
492ae7408fSSathya Perla {
502ae7408fSSathya Perla struct bnxt *bp;
512ae7408fSSathya Perla
522ae7408fSSathya Perla /* check if dev belongs to the same switch */
5352d5254aSFlorian Fainelli if (!netdev_port_same_parent_id(pf_bp->dev, dev)) {
549a005c38SJonathan Lemon netdev_info(pf_bp->dev, "dev(ifindex=%d) not on same switch\n",
552ae7408fSSathya Perla dev->ifindex);
562ae7408fSSathya Perla return BNXT_FID_INVALID;
572ae7408fSSathya Perla }
582ae7408fSSathya Perla
592ae7408fSSathya Perla /* Is dev a VF-rep? */
60dd4ea1daSSathya Perla if (bnxt_dev_is_vf_rep(dev))
612ae7408fSSathya Perla return bnxt_vf_rep_get_fid(dev);
622ae7408fSSathya Perla
632ae7408fSSathya Perla bp = netdev_priv(dev);
642ae7408fSSathya Perla return bp->pf.fw_fid;
652ae7408fSSathya Perla }
662ae7408fSSathya Perla
bnxt_tc_parse_redir(struct bnxt * bp,struct bnxt_tc_actions * actions,const struct flow_action_entry * act)672ae7408fSSathya Perla static int bnxt_tc_parse_redir(struct bnxt *bp,
682ae7408fSSathya Perla struct bnxt_tc_actions *actions,
6973867881SPablo Neira Ayuso const struct flow_action_entry *act)
702ae7408fSSathya Perla {
7173867881SPablo Neira Ayuso struct net_device *dev = act->dev;
722ae7408fSSathya Perla
732ae7408fSSathya Perla if (!dev) {
749a005c38SJonathan Lemon netdev_info(bp->dev, "no dev in mirred action\n");
752ae7408fSSathya Perla return -EINVAL;
762ae7408fSSathya Perla }
772ae7408fSSathya Perla
782ae7408fSSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_FWD;
792ae7408fSSathya Perla actions->dst_dev = dev;
802ae7408fSSathya Perla return 0;
812ae7408fSSathya Perla }
822ae7408fSSathya Perla
bnxt_tc_parse_vlan(struct bnxt * bp,struct bnxt_tc_actions * actions,const struct flow_action_entry * act)838c6ec361SDavide Caratti static int bnxt_tc_parse_vlan(struct bnxt *bp,
842ae7408fSSathya Perla struct bnxt_tc_actions *actions,
8573867881SPablo Neira Ayuso const struct flow_action_entry *act)
862ae7408fSSathya Perla {
8773867881SPablo Neira Ayuso switch (act->id) {
8873867881SPablo Neira Ayuso case FLOW_ACTION_VLAN_POP:
892ae7408fSSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_POP_VLAN;
908c6ec361SDavide Caratti break;
9173867881SPablo Neira Ayuso case FLOW_ACTION_VLAN_PUSH:
922ae7408fSSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_PUSH_VLAN;
9373867881SPablo Neira Ayuso actions->push_vlan_tci = htons(act->vlan.vid);
9473867881SPablo Neira Ayuso actions->push_vlan_tpid = act->vlan.proto;
958c6ec361SDavide Caratti break;
968c6ec361SDavide Caratti default:
978c6ec361SDavide Caratti return -EOPNOTSUPP;
982ae7408fSSathya Perla }
998c6ec361SDavide Caratti return 0;
1002ae7408fSSathya Perla }
1012ae7408fSSathya Perla
bnxt_tc_parse_tunnel_set(struct bnxt * bp,struct bnxt_tc_actions * actions,const struct flow_action_entry * act)1028c95f773SSathya Perla static int bnxt_tc_parse_tunnel_set(struct bnxt *bp,
1038c95f773SSathya Perla struct bnxt_tc_actions *actions,
10473867881SPablo Neira Ayuso const struct flow_action_entry *act)
1058c95f773SSathya Perla {
10673867881SPablo Neira Ayuso const struct ip_tunnel_info *tun_info = act->tunnel;
10773867881SPablo Neira Ayuso const struct ip_tunnel_key *tun_key = &tun_info->key;
1088c95f773SSathya Perla
1098c95f773SSathya Perla if (ip_tunnel_info_af(tun_info) != AF_INET) {
1109a005c38SJonathan Lemon netdev_info(bp->dev, "only IPv4 tunnel-encap is supported\n");
1118c95f773SSathya Perla return -EOPNOTSUPP;
1128c95f773SSathya Perla }
1138c95f773SSathya Perla
1148c95f773SSathya Perla actions->tun_encap_key = *tun_key;
1158c95f773SSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP;
1168c95f773SSathya Perla return 0;
1178c95f773SSathya Perla }
1188c95f773SSathya Perla
1199b9eb518SSomnath Kotur /* Key & Mask from the stack comes unaligned in multiple iterations of 4 bytes
1209b9eb518SSomnath Kotur * each(u32).
12190f90624SVenkat Duvvuru * This routine consolidates such multiple unaligned values into one
12290f90624SVenkat Duvvuru * field each for Key & Mask (for src and dst macs separately)
12390f90624SVenkat Duvvuru * For example,
12490f90624SVenkat Duvvuru * Mask/Key Offset Iteration
12590f90624SVenkat Duvvuru * ========== ====== =========
12690f90624SVenkat Duvvuru * dst mac 0xffffffff 0 1
12790f90624SVenkat Duvvuru * dst mac 0x0000ffff 4 2
12890f90624SVenkat Duvvuru *
12990f90624SVenkat Duvvuru * src mac 0xffff0000 4 1
13090f90624SVenkat Duvvuru * src mac 0xffffffff 8 2
13190f90624SVenkat Duvvuru *
13290f90624SVenkat Duvvuru * The above combination coming from the stack will be consolidated as
13390f90624SVenkat Duvvuru * Mask/Key
13490f90624SVenkat Duvvuru * ==============
13590f90624SVenkat Duvvuru * src mac: 0xffffffffffff
13690f90624SVenkat Duvvuru * dst mac: 0xffffffffffff
13790f90624SVenkat Duvvuru */
bnxt_set_l2_key_mask(u32 part_key,u32 part_mask,u8 * actual_key,u8 * actual_mask)13890f90624SVenkat Duvvuru static void bnxt_set_l2_key_mask(u32 part_key, u32 part_mask,
13990f90624SVenkat Duvvuru u8 *actual_key, u8 *actual_mask)
14090f90624SVenkat Duvvuru {
14190f90624SVenkat Duvvuru u32 key = get_unaligned((u32 *)actual_key);
14290f90624SVenkat Duvvuru u32 mask = get_unaligned((u32 *)actual_mask);
14390f90624SVenkat Duvvuru
14490f90624SVenkat Duvvuru part_key &= part_mask;
14590f90624SVenkat Duvvuru part_key |= key & ~part_mask;
14690f90624SVenkat Duvvuru
14790f90624SVenkat Duvvuru put_unaligned(mask | part_mask, (u32 *)actual_mask);
14890f90624SVenkat Duvvuru put_unaligned(part_key, (u32 *)actual_key);
14990f90624SVenkat Duvvuru }
15090f90624SVenkat Duvvuru
15190f90624SVenkat Duvvuru static int
bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions * actions,u16 * eth_addr,u16 * eth_addr_mask)15290f90624SVenkat Duvvuru bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions,
15390f90624SVenkat Duvvuru u16 *eth_addr, u16 *eth_addr_mask)
15490f90624SVenkat Duvvuru {
15590f90624SVenkat Duvvuru u16 *p;
15690f90624SVenkat Duvvuru int j;
15790f90624SVenkat Duvvuru
15890f90624SVenkat Duvvuru if (unlikely(bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask)))
15990f90624SVenkat Duvvuru return -EINVAL;
16090f90624SVenkat Duvvuru
16190f90624SVenkat Duvvuru if (!is_wildcard(ð_addr_mask[0], ETH_ALEN)) {
16290f90624SVenkat Duvvuru if (!is_exactmatch(ð_addr_mask[0], ETH_ALEN))
16390f90624SVenkat Duvvuru return -EINVAL;
16490f90624SVenkat Duvvuru /* FW expects dmac to be in u16 array format */
16590f90624SVenkat Duvvuru p = eth_addr;
16690f90624SVenkat Duvvuru for (j = 0; j < 3; j++)
16790f90624SVenkat Duvvuru actions->l2_rewrite_dmac[j] = cpu_to_be16(*(p + j));
16890f90624SVenkat Duvvuru }
16990f90624SVenkat Duvvuru
1703128aad1SVenkat Duvvuru if (!is_wildcard(ð_addr_mask[ETH_ALEN / 2], ETH_ALEN)) {
1713128aad1SVenkat Duvvuru if (!is_exactmatch(ð_addr_mask[ETH_ALEN / 2], ETH_ALEN))
17290f90624SVenkat Duvvuru return -EINVAL;
17390f90624SVenkat Duvvuru /* FW expects smac to be in u16 array format */
17490f90624SVenkat Duvvuru p = ð_addr[ETH_ALEN / 2];
17590f90624SVenkat Duvvuru for (j = 0; j < 3; j++)
17690f90624SVenkat Duvvuru actions->l2_rewrite_smac[j] = cpu_to_be16(*(p + j));
17790f90624SVenkat Duvvuru }
17890f90624SVenkat Duvvuru
17990f90624SVenkat Duvvuru return 0;
18090f90624SVenkat Duvvuru }
18190f90624SVenkat Duvvuru
18290f90624SVenkat Duvvuru static int
bnxt_tc_parse_pedit(struct bnxt * bp,struct bnxt_tc_actions * actions,struct flow_action_entry * act,int act_idx,u8 * eth_addr,u8 * eth_addr_mask)18390f90624SVenkat Duvvuru bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions,
1849b9eb518SSomnath Kotur struct flow_action_entry *act, int act_idx, u8 *eth_addr,
18590f90624SVenkat Duvvuru u8 *eth_addr_mask)
18690f90624SVenkat Duvvuru {
1879b9eb518SSomnath Kotur size_t offset_of_ip6_daddr = offsetof(struct ipv6hdr, daddr);
1889b9eb518SSomnath Kotur size_t offset_of_ip6_saddr = offsetof(struct ipv6hdr, saddr);
1899b9eb518SSomnath Kotur u32 mask, val, offset, idx;
19090f90624SVenkat Duvvuru u8 htype;
19190f90624SVenkat Duvvuru
19290f90624SVenkat Duvvuru offset = act->mangle.offset;
19390f90624SVenkat Duvvuru htype = act->mangle.htype;
1949b9eb518SSomnath Kotur mask = ~act->mangle.mask;
1959b9eb518SSomnath Kotur val = act->mangle.val;
1969b9eb518SSomnath Kotur
19790f90624SVenkat Duvvuru switch (htype) {
19890f90624SVenkat Duvvuru case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
19990f90624SVenkat Duvvuru if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) {
20090f90624SVenkat Duvvuru netdev_err(bp->dev,
20190f90624SVenkat Duvvuru "%s: eth_hdr: Invalid pedit field\n",
20290f90624SVenkat Duvvuru __func__);
20390f90624SVenkat Duvvuru return -EINVAL;
20490f90624SVenkat Duvvuru }
20590f90624SVenkat Duvvuru actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE;
20690f90624SVenkat Duvvuru
20790f90624SVenkat Duvvuru bnxt_set_l2_key_mask(val, mask, ð_addr[offset],
20890f90624SVenkat Duvvuru ð_addr_mask[offset]);
20990f90624SVenkat Duvvuru break;
2109b9eb518SSomnath Kotur case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
2119b9eb518SSomnath Kotur actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE;
2129b9eb518SSomnath Kotur actions->nat.l3_is_ipv4 = true;
2139b9eb518SSomnath Kotur if (offset == offsetof(struct iphdr, saddr)) {
2149b9eb518SSomnath Kotur actions->nat.src_xlate = true;
2159b9eb518SSomnath Kotur actions->nat.l3.ipv4.saddr.s_addr = htonl(val);
2169b9eb518SSomnath Kotur } else if (offset == offsetof(struct iphdr, daddr)) {
2179b9eb518SSomnath Kotur actions->nat.src_xlate = false;
2189b9eb518SSomnath Kotur actions->nat.l3.ipv4.daddr.s_addr = htonl(val);
2199b9eb518SSomnath Kotur } else {
2209b9eb518SSomnath Kotur netdev_err(bp->dev,
2219b9eb518SSomnath Kotur "%s: IPv4_hdr: Invalid pedit field\n",
2229b9eb518SSomnath Kotur __func__);
2239b9eb518SSomnath Kotur return -EINVAL;
2249b9eb518SSomnath Kotur }
2259b9eb518SSomnath Kotur
2269b9eb518SSomnath Kotur netdev_dbg(bp->dev, "nat.src_xlate = %d src IP: %pI4 dst ip : %pI4\n",
2279b9eb518SSomnath Kotur actions->nat.src_xlate, &actions->nat.l3.ipv4.saddr,
2289b9eb518SSomnath Kotur &actions->nat.l3.ipv4.daddr);
2299b9eb518SSomnath Kotur break;
2309b9eb518SSomnath Kotur
2319b9eb518SSomnath Kotur case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
2329b9eb518SSomnath Kotur actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE;
2339b9eb518SSomnath Kotur actions->nat.l3_is_ipv4 = false;
2349b9eb518SSomnath Kotur if (offset >= offsetof(struct ipv6hdr, saddr) &&
2359b9eb518SSomnath Kotur offset < offset_of_ip6_daddr) {
2369b9eb518SSomnath Kotur /* 16 byte IPv6 address comes in 4 iterations of
2379b9eb518SSomnath Kotur * 4byte chunks each
2389b9eb518SSomnath Kotur */
2399b9eb518SSomnath Kotur actions->nat.src_xlate = true;
2409b9eb518SSomnath Kotur idx = (offset - offset_of_ip6_saddr) / 4;
2419b9eb518SSomnath Kotur /* First 4bytes will be copied to idx 0 and so on */
2429b9eb518SSomnath Kotur actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val);
2439b9eb518SSomnath Kotur } else if (offset >= offset_of_ip6_daddr &&
2449b9eb518SSomnath Kotur offset < offset_of_ip6_daddr + 16) {
2459b9eb518SSomnath Kotur actions->nat.src_xlate = false;
2469b9eb518SSomnath Kotur idx = (offset - offset_of_ip6_daddr) / 4;
2479b9eb518SSomnath Kotur actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val);
2489b9eb518SSomnath Kotur } else {
2499b9eb518SSomnath Kotur netdev_err(bp->dev,
2509b9eb518SSomnath Kotur "%s: IPv6_hdr: Invalid pedit field\n",
2519b9eb518SSomnath Kotur __func__);
2529b9eb518SSomnath Kotur return -EINVAL;
2539b9eb518SSomnath Kotur }
2549b9eb518SSomnath Kotur break;
2559b9eb518SSomnath Kotur case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
2569b9eb518SSomnath Kotur case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
2579b9eb518SSomnath Kotur /* HW does not support L4 rewrite alone without L3
2589b9eb518SSomnath Kotur * rewrite
2599b9eb518SSomnath Kotur */
2609b9eb518SSomnath Kotur if (!(actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE)) {
2619b9eb518SSomnath Kotur netdev_err(bp->dev,
2629b9eb518SSomnath Kotur "Need to specify L3 rewrite as well\n");
2639b9eb518SSomnath Kotur return -EINVAL;
2649b9eb518SSomnath Kotur }
2659b9eb518SSomnath Kotur if (actions->nat.src_xlate)
2669b9eb518SSomnath Kotur actions->nat.l4.ports.sport = htons(val);
2679b9eb518SSomnath Kotur else
2689b9eb518SSomnath Kotur actions->nat.l4.ports.dport = htons(val);
2699b9eb518SSomnath Kotur netdev_dbg(bp->dev, "actions->nat.sport = %d dport = %d\n",
2709b9eb518SSomnath Kotur actions->nat.l4.ports.sport,
2719b9eb518SSomnath Kotur actions->nat.l4.ports.dport);
2729b9eb518SSomnath Kotur break;
27390f90624SVenkat Duvvuru default:
27490f90624SVenkat Duvvuru netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n",
27590f90624SVenkat Duvvuru __func__);
27690f90624SVenkat Duvvuru return -EINVAL;
27790f90624SVenkat Duvvuru }
27890f90624SVenkat Duvvuru return 0;
27990f90624SVenkat Duvvuru }
28090f90624SVenkat Duvvuru
bnxt_tc_parse_actions(struct bnxt * bp,struct bnxt_tc_actions * actions,struct flow_action * flow_action,struct netlink_ext_ack * extack)2812ae7408fSSathya Perla static int bnxt_tc_parse_actions(struct bnxt *bp,
2822ae7408fSSathya Perla struct bnxt_tc_actions *actions,
283319a1d19SJiri Pirko struct flow_action *flow_action,
284319a1d19SJiri Pirko struct netlink_ext_ack *extack)
2852ae7408fSSathya Perla {
28690f90624SVenkat Duvvuru /* Used to store the L2 rewrite mask for dmac (6 bytes) followed by
28790f90624SVenkat Duvvuru * smac (6 bytes) if rewrite of both is specified, otherwise either
28890f90624SVenkat Duvvuru * dmac or smac
28990f90624SVenkat Duvvuru */
29090f90624SVenkat Duvvuru u16 eth_addr_mask[ETH_ALEN] = { 0 };
29190f90624SVenkat Duvvuru /* Used to store the L2 rewrite key for dmac (6 bytes) followed by
29290f90624SVenkat Duvvuru * smac (6 bytes) if rewrite of both is specified, otherwise either
29390f90624SVenkat Duvvuru * dmac or smac
29490f90624SVenkat Duvvuru */
29590f90624SVenkat Duvvuru u16 eth_addr[ETH_ALEN] = { 0 };
29673867881SPablo Neira Ayuso struct flow_action_entry *act;
297244cd96aSCong Wang int i, rc;
2982ae7408fSSathya Perla
29973867881SPablo Neira Ayuso if (!flow_action_has_entries(flow_action)) {
3009a005c38SJonathan Lemon netdev_info(bp->dev, "no actions\n");
3012ae7408fSSathya Perla return -EINVAL;
3022ae7408fSSathya Perla }
3032ae7408fSSathya Perla
30453eca1f3SJakub Kicinski if (!flow_action_basic_hw_stats_check(flow_action, extack))
305319a1d19SJiri Pirko return -EOPNOTSUPP;
306319a1d19SJiri Pirko
30773867881SPablo Neira Ayuso flow_action_for_each(i, act, flow_action) {
30873867881SPablo Neira Ayuso switch (act->id) {
30973867881SPablo Neira Ayuso case FLOW_ACTION_DROP:
3102ae7408fSSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_DROP;
3112ae7408fSSathya Perla return 0; /* don't bother with other actions */
31273867881SPablo Neira Ayuso case FLOW_ACTION_REDIRECT:
31373867881SPablo Neira Ayuso rc = bnxt_tc_parse_redir(bp, actions, act);
3142ae7408fSSathya Perla if (rc)
3152ae7408fSSathya Perla return rc;
31673867881SPablo Neira Ayuso break;
31773867881SPablo Neira Ayuso case FLOW_ACTION_VLAN_POP:
31873867881SPablo Neira Ayuso case FLOW_ACTION_VLAN_PUSH:
31973867881SPablo Neira Ayuso case FLOW_ACTION_VLAN_MANGLE:
32073867881SPablo Neira Ayuso rc = bnxt_tc_parse_vlan(bp, actions, act);
3218c6ec361SDavide Caratti if (rc)
3228c6ec361SDavide Caratti return rc;
32373867881SPablo Neira Ayuso break;
32473867881SPablo Neira Ayuso case FLOW_ACTION_TUNNEL_ENCAP:
32573867881SPablo Neira Ayuso rc = bnxt_tc_parse_tunnel_set(bp, actions, act);
3268c95f773SSathya Perla if (rc)
3278c95f773SSathya Perla return rc;
32873867881SPablo Neira Ayuso break;
32973867881SPablo Neira Ayuso case FLOW_ACTION_TUNNEL_DECAP:
3308c95f773SSathya Perla actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_DECAP;
33173867881SPablo Neira Ayuso break;
33290f90624SVenkat Duvvuru /* Packet edit: L2 rewrite, NAT, NAPT */
33390f90624SVenkat Duvvuru case FLOW_ACTION_MANGLE:
3349b9eb518SSomnath Kotur rc = bnxt_tc_parse_pedit(bp, actions, act, i,
33590f90624SVenkat Duvvuru (u8 *)eth_addr,
33690f90624SVenkat Duvvuru (u8 *)eth_addr_mask);
33790f90624SVenkat Duvvuru if (rc)
33890f90624SVenkat Duvvuru return rc;
33990f90624SVenkat Duvvuru break;
34073867881SPablo Neira Ayuso default:
34173867881SPablo Neira Ayuso break;
3428c95f773SSathya Perla }
3438c95f773SSathya Perla }
3448c95f773SSathya Perla
34590f90624SVenkat Duvvuru if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) {
34690f90624SVenkat Duvvuru rc = bnxt_fill_l2_rewrite_fields(actions, eth_addr,
34790f90624SVenkat Duvvuru eth_addr_mask);
34890f90624SVenkat Duvvuru if (rc)
34990f90624SVenkat Duvvuru return rc;
35090f90624SVenkat Duvvuru }
35190f90624SVenkat Duvvuru
352e9ecc731SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) {
353e9ecc731SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
354e9ecc731SSathya Perla /* dst_fid is PF's fid */
355e9ecc731SSathya Perla actions->dst_fid = bp->pf.fw_fid;
356e9ecc731SSathya Perla } else {
357e9ecc731SSathya Perla /* find the FID from dst_dev */
358e9ecc731SSathya Perla actions->dst_fid =
359e9ecc731SSathya Perla bnxt_flow_get_dst_fid(bp, actions->dst_dev);
360e9ecc731SSathya Perla if (actions->dst_fid == BNXT_FID_INVALID)
3618c95f773SSathya Perla return -EINVAL;
3628c95f773SSathya Perla }
363e9ecc731SSathya Perla }
3648c95f773SSathya Perla
36592425c40SDan Carpenter return 0;
3662ae7408fSSathya Perla }
3672ae7408fSSathya Perla
bnxt_tc_parse_flow(struct bnxt * bp,struct flow_cls_offload * tc_flow_cmd,struct bnxt_tc_flow * flow)3682ae7408fSSathya Perla static int bnxt_tc_parse_flow(struct bnxt *bp,
369f9e30088SPablo Neira Ayuso struct flow_cls_offload *tc_flow_cmd,
3702ae7408fSSathya Perla struct bnxt_tc_flow *flow)
3712ae7408fSSathya Perla {
372f9e30088SPablo Neira Ayuso struct flow_rule *rule = flow_cls_offload_flow_rule(tc_flow_cmd);
3738f256622SPablo Neira Ayuso struct flow_dissector *dissector = rule->match.dissector;
3742ae7408fSSathya Perla
3752ae7408fSSathya Perla /* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
3762b3082c6SRatheesh Kannoth if ((dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
3772b3082c6SRatheesh Kannoth (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
3782b3082c6SRatheesh Kannoth netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%llx\n",
3792ae7408fSSathya Perla dissector->used_keys);
3802ae7408fSSathya Perla return -EOPNOTSUPP;
3812ae7408fSSathya Perla }
3822ae7408fSSathya Perla
3838f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
3848f256622SPablo Neira Ayuso struct flow_match_basic match;
3852ae7408fSSathya Perla
3868f256622SPablo Neira Ayuso flow_rule_match_basic(rule, &match);
3878f256622SPablo Neira Ayuso flow->l2_key.ether_type = match.key->n_proto;
3888f256622SPablo Neira Ayuso flow->l2_mask.ether_type = match.mask->n_proto;
3892ae7408fSSathya Perla
3908f256622SPablo Neira Ayuso if (match.key->n_proto == htons(ETH_P_IP) ||
3918f256622SPablo Neira Ayuso match.key->n_proto == htons(ETH_P_IPV6)) {
3928f256622SPablo Neira Ayuso flow->l4_key.ip_proto = match.key->ip_proto;
3938f256622SPablo Neira Ayuso flow->l4_mask.ip_proto = match.mask->ip_proto;
3942ae7408fSSathya Perla }
3952ae7408fSSathya Perla }
3962ae7408fSSathya Perla
3978f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
3988f256622SPablo Neira Ayuso struct flow_match_eth_addrs match;
3992ae7408fSSathya Perla
4008f256622SPablo Neira Ayuso flow_rule_match_eth_addrs(rule, &match);
4012ae7408fSSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_ETH_ADDRS;
4028f256622SPablo Neira Ayuso ether_addr_copy(flow->l2_key.dmac, match.key->dst);
4038f256622SPablo Neira Ayuso ether_addr_copy(flow->l2_mask.dmac, match.mask->dst);
4048f256622SPablo Neira Ayuso ether_addr_copy(flow->l2_key.smac, match.key->src);
4058f256622SPablo Neira Ayuso ether_addr_copy(flow->l2_mask.smac, match.mask->src);
4062ae7408fSSathya Perla }
4072ae7408fSSathya Perla
4088f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
4098f256622SPablo Neira Ayuso struct flow_match_vlan match;
4102ae7408fSSathya Perla
4118f256622SPablo Neira Ayuso flow_rule_match_vlan(rule, &match);
4122ae7408fSSathya Perla flow->l2_key.inner_vlan_tci =
4138f256622SPablo Neira Ayuso cpu_to_be16(VLAN_TCI(match.key->vlan_id,
4148f256622SPablo Neira Ayuso match.key->vlan_priority));
4152ae7408fSSathya Perla flow->l2_mask.inner_vlan_tci =
4168f256622SPablo Neira Ayuso cpu_to_be16((VLAN_TCI(match.mask->vlan_id,
4178f256622SPablo Neira Ayuso match.mask->vlan_priority)));
4182ae7408fSSathya Perla flow->l2_key.inner_vlan_tpid = htons(ETH_P_8021Q);
4192ae7408fSSathya Perla flow->l2_mask.inner_vlan_tpid = htons(0xffff);
4202ae7408fSSathya Perla flow->l2_key.num_vlans = 1;
4212ae7408fSSathya Perla }
4222ae7408fSSathya Perla
4238f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
4248f256622SPablo Neira Ayuso struct flow_match_ipv4_addrs match;
4252ae7408fSSathya Perla
4268f256622SPablo Neira Ayuso flow_rule_match_ipv4_addrs(rule, &match);
4272ae7408fSSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_IPV4_ADDRS;
4288f256622SPablo Neira Ayuso flow->l3_key.ipv4.daddr.s_addr = match.key->dst;
4298f256622SPablo Neira Ayuso flow->l3_mask.ipv4.daddr.s_addr = match.mask->dst;
4308f256622SPablo Neira Ayuso flow->l3_key.ipv4.saddr.s_addr = match.key->src;
4318f256622SPablo Neira Ayuso flow->l3_mask.ipv4.saddr.s_addr = match.mask->src;
4328f256622SPablo Neira Ayuso } else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
4338f256622SPablo Neira Ayuso struct flow_match_ipv6_addrs match;
4342ae7408fSSathya Perla
4358f256622SPablo Neira Ayuso flow_rule_match_ipv6_addrs(rule, &match);
4362ae7408fSSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_IPV6_ADDRS;
4378f256622SPablo Neira Ayuso flow->l3_key.ipv6.daddr = match.key->dst;
4388f256622SPablo Neira Ayuso flow->l3_mask.ipv6.daddr = match.mask->dst;
4398f256622SPablo Neira Ayuso flow->l3_key.ipv6.saddr = match.key->src;
4408f256622SPablo Neira Ayuso flow->l3_mask.ipv6.saddr = match.mask->src;
4412ae7408fSSathya Perla }
4422ae7408fSSathya Perla
4438f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
4448f256622SPablo Neira Ayuso struct flow_match_ports match;
4452ae7408fSSathya Perla
4468f256622SPablo Neira Ayuso flow_rule_match_ports(rule, &match);
4472ae7408fSSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_PORTS;
4488f256622SPablo Neira Ayuso flow->l4_key.ports.dport = match.key->dst;
4498f256622SPablo Neira Ayuso flow->l4_mask.ports.dport = match.mask->dst;
4508f256622SPablo Neira Ayuso flow->l4_key.ports.sport = match.key->src;
4518f256622SPablo Neira Ayuso flow->l4_mask.ports.sport = match.mask->src;
4522ae7408fSSathya Perla }
4532ae7408fSSathya Perla
4548f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP)) {
4558f256622SPablo Neira Ayuso struct flow_match_icmp match;
4562ae7408fSSathya Perla
4578f256622SPablo Neira Ayuso flow_rule_match_icmp(rule, &match);
4582ae7408fSSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_ICMP;
4598f256622SPablo Neira Ayuso flow->l4_key.icmp.type = match.key->type;
4608f256622SPablo Neira Ayuso flow->l4_key.icmp.code = match.key->code;
4618f256622SPablo Neira Ayuso flow->l4_mask.icmp.type = match.mask->type;
4628f256622SPablo Neira Ayuso flow->l4_mask.icmp.code = match.mask->code;
4632ae7408fSSathya Perla }
4642ae7408fSSathya Perla
4658f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
4668f256622SPablo Neira Ayuso struct flow_match_ipv4_addrs match;
4678c95f773SSathya Perla
4688f256622SPablo Neira Ayuso flow_rule_match_enc_ipv4_addrs(rule, &match);
4698c95f773SSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_IPV4_ADDRS;
4708f256622SPablo Neira Ayuso flow->tun_key.u.ipv4.dst = match.key->dst;
4718f256622SPablo Neira Ayuso flow->tun_mask.u.ipv4.dst = match.mask->dst;
4728f256622SPablo Neira Ayuso flow->tun_key.u.ipv4.src = match.key->src;
4738f256622SPablo Neira Ayuso flow->tun_mask.u.ipv4.src = match.mask->src;
4748f256622SPablo Neira Ayuso } else if (flow_rule_match_key(rule,
4758c95f773SSathya Perla FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
4768c95f773SSathya Perla return -EOPNOTSUPP;
4778c95f773SSathya Perla }
4788c95f773SSathya Perla
4798f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
4808f256622SPablo Neira Ayuso struct flow_match_enc_keyid match;
4818c95f773SSathya Perla
4828f256622SPablo Neira Ayuso flow_rule_match_enc_keyid(rule, &match);
4838c95f773SSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_ID;
4848f256622SPablo Neira Ayuso flow->tun_key.tun_id = key32_to_tunnel_id(match.key->keyid);
4858f256622SPablo Neira Ayuso flow->tun_mask.tun_id = key32_to_tunnel_id(match.mask->keyid);
4868c95f773SSathya Perla }
4878c95f773SSathya Perla
4888f256622SPablo Neira Ayuso if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
4898f256622SPablo Neira Ayuso struct flow_match_ports match;
4908c95f773SSathya Perla
4918f256622SPablo Neira Ayuso flow_rule_match_enc_ports(rule, &match);
4928c95f773SSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_PORTS;
4938f256622SPablo Neira Ayuso flow->tun_key.tp_dst = match.key->dst;
4948f256622SPablo Neira Ayuso flow->tun_mask.tp_dst = match.mask->dst;
4958f256622SPablo Neira Ayuso flow->tun_key.tp_src = match.key->src;
4968f256622SPablo Neira Ayuso flow->tun_mask.tp_src = match.mask->src;
4978c95f773SSathya Perla }
4988c95f773SSathya Perla
499319a1d19SJiri Pirko return bnxt_tc_parse_actions(bp, &flow->actions, &rule->action,
500319a1d19SJiri Pirko tc_flow_cmd->common.extack);
5012ae7408fSSathya Perla }
5022ae7408fSSathya Perla
bnxt_hwrm_cfa_flow_free(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node)503abd43a13SVenkat Duvvuru static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
504abd43a13SVenkat Duvvuru struct bnxt_tc_flow_node *flow_node)
5052ae7408fSSathya Perla {
506bbf33d1dSEdwin Peer struct hwrm_cfa_flow_free_input *req;
507db1d36a2SSathya Perla int rc;
508db1d36a2SSathya Perla
509bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_FLOW_FREE);
510bbf33d1dSEdwin Peer if (!rc) {
511abd43a13SVenkat Duvvuru if (bp->fw_cap & BNXT_FW_CAP_OVS_64BIT_HANDLE)
512bbf33d1dSEdwin Peer req->ext_flow_handle = flow_node->ext_flow_handle;
513abd43a13SVenkat Duvvuru else
514bbf33d1dSEdwin Peer req->flow_handle = flow_node->flow_handle;
515db1d36a2SSathya Perla
516bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req);
517bbf33d1dSEdwin Peer }
518db1d36a2SSathya Perla if (rc)
5199a005c38SJonathan Lemon netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
5206ae777eaSVenkat Duvvuru
521db1d36a2SSathya Perla return rc;
522db1d36a2SSathya Perla }
523db1d36a2SSathya Perla
ipv6_mask_len(struct in6_addr * mask)524db1d36a2SSathya Perla static int ipv6_mask_len(struct in6_addr *mask)
525db1d36a2SSathya Perla {
526db1d36a2SSathya Perla int mask_len = 0, i;
527db1d36a2SSathya Perla
528db1d36a2SSathya Perla for (i = 0; i < 4; i++)
529db1d36a2SSathya Perla mask_len += inet_mask_len(mask->s6_addr32[i]);
530db1d36a2SSathya Perla
531db1d36a2SSathya Perla return mask_len;
532db1d36a2SSathya Perla }
533db1d36a2SSathya Perla
is_wildcard(void * mask,int len)534db1d36a2SSathya Perla static bool is_wildcard(void *mask, int len)
535db1d36a2SSathya Perla {
536db1d36a2SSathya Perla const u8 *p = mask;
537db1d36a2SSathya Perla int i;
538db1d36a2SSathya Perla
539db1d36a2SSathya Perla for (i = 0; i < len; i++) {
540db1d36a2SSathya Perla if (p[i] != 0)
541db1d36a2SSathya Perla return false;
542db1d36a2SSathya Perla }
543db1d36a2SSathya Perla return true;
5442ae7408fSSathya Perla }
5452ae7408fSSathya Perla
is_exactmatch(void * mask,int len)546e85a9be9SAndy Gospodarek static bool is_exactmatch(void *mask, int len)
547e85a9be9SAndy Gospodarek {
548e85a9be9SAndy Gospodarek const u8 *p = mask;
549e85a9be9SAndy Gospodarek int i;
550e85a9be9SAndy Gospodarek
551e85a9be9SAndy Gospodarek for (i = 0; i < len; i++)
552e85a9be9SAndy Gospodarek if (p[i] != 0xff)
553e85a9be9SAndy Gospodarek return false;
554e85a9be9SAndy Gospodarek
555e85a9be9SAndy Gospodarek return true;
556e85a9be9SAndy Gospodarek }
557e85a9be9SAndy Gospodarek
is_vlan_tci_allowed(__be16 vlan_tci_mask,__be16 vlan_tci)558e32d4e60SVenkat Duvvuru static bool is_vlan_tci_allowed(__be16 vlan_tci_mask,
559e32d4e60SVenkat Duvvuru __be16 vlan_tci)
560e32d4e60SVenkat Duvvuru {
561e32d4e60SVenkat Duvvuru /* VLAN priority must be either exactly zero or fully wildcarded and
562e32d4e60SVenkat Duvvuru * VLAN id must be exact match.
563e32d4e60SVenkat Duvvuru */
564e32d4e60SVenkat Duvvuru if (is_vid_exactmatch(vlan_tci_mask) &&
565e32d4e60SVenkat Duvvuru ((is_vlan_pcp_exactmatch(vlan_tci_mask) &&
566e32d4e60SVenkat Duvvuru is_vlan_pcp_zero(vlan_tci)) ||
567e32d4e60SVenkat Duvvuru is_vlan_pcp_wildcarded(vlan_tci_mask)))
568e32d4e60SVenkat Duvvuru return true;
569e32d4e60SVenkat Duvvuru
570e32d4e60SVenkat Duvvuru return false;
571e32d4e60SVenkat Duvvuru }
572e32d4e60SVenkat Duvvuru
bits_set(void * key,int len)573e85a9be9SAndy Gospodarek static bool bits_set(void *key, int len)
574e85a9be9SAndy Gospodarek {
575e85a9be9SAndy Gospodarek const u8 *p = key;
576e85a9be9SAndy Gospodarek int i;
577e85a9be9SAndy Gospodarek
578e85a9be9SAndy Gospodarek for (i = 0; i < len; i++)
579e85a9be9SAndy Gospodarek if (p[i] != 0)
580e85a9be9SAndy Gospodarek return true;
581e85a9be9SAndy Gospodarek
582e85a9be9SAndy Gospodarek return false;
583e85a9be9SAndy Gospodarek }
584e85a9be9SAndy Gospodarek
bnxt_hwrm_cfa_flow_alloc(struct bnxt * bp,struct bnxt_tc_flow * flow,__le16 ref_flow_handle,__le32 tunnel_handle,struct bnxt_tc_flow_node * flow_node)5852ae7408fSSathya Perla static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow,
5868c95f773SSathya Perla __le16 ref_flow_handle,
587abd43a13SVenkat Duvvuru __le32 tunnel_handle,
588abd43a13SVenkat Duvvuru struct bnxt_tc_flow_node *flow_node)
5892ae7408fSSathya Perla {
590db1d36a2SSathya Perla struct bnxt_tc_actions *actions = &flow->actions;
591db1d36a2SSathya Perla struct bnxt_tc_l3_key *l3_mask = &flow->l3_mask;
592db1d36a2SSathya Perla struct bnxt_tc_l3_key *l3_key = &flow->l3_key;
5935c209fc8SVenkat Duvvuru struct hwrm_cfa_flow_alloc_output *resp;
594bbf33d1dSEdwin Peer struct hwrm_cfa_flow_alloc_input *req;
595db1d36a2SSathya Perla u16 flow_flags = 0, action_flags = 0;
596db1d36a2SSathya Perla int rc;
597db1d36a2SSathya Perla
598bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_FLOW_ALLOC);
599bbf33d1dSEdwin Peer if (rc)
600bbf33d1dSEdwin Peer return rc;
601db1d36a2SSathya Perla
602bbf33d1dSEdwin Peer req->src_fid = cpu_to_le16(flow->src_fid);
603bbf33d1dSEdwin Peer req->ref_flow_handle = ref_flow_handle;
6048c95f773SSathya Perla
60590f90624SVenkat Duvvuru if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) {
606bbf33d1dSEdwin Peer memcpy(req->l2_rewrite_dmac, actions->l2_rewrite_dmac,
60790f90624SVenkat Duvvuru ETH_ALEN);
608bbf33d1dSEdwin Peer memcpy(req->l2_rewrite_smac, actions->l2_rewrite_smac,
60990f90624SVenkat Duvvuru ETH_ALEN);
61090f90624SVenkat Duvvuru action_flags |=
61190f90624SVenkat Duvvuru CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE;
61290f90624SVenkat Duvvuru }
61390f90624SVenkat Duvvuru
6149b9eb518SSomnath Kotur if (actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE) {
6159b9eb518SSomnath Kotur if (actions->nat.l3_is_ipv4) {
6169b9eb518SSomnath Kotur action_flags |=
6179b9eb518SSomnath Kotur CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS;
6189b9eb518SSomnath Kotur
6199b9eb518SSomnath Kotur if (actions->nat.src_xlate) {
6209b9eb518SSomnath Kotur action_flags |=
6219b9eb518SSomnath Kotur CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC;
6229b9eb518SSomnath Kotur /* L3 source rewrite */
623bbf33d1dSEdwin Peer req->nat_ip_address[0] =
6249b9eb518SSomnath Kotur actions->nat.l3.ipv4.saddr.s_addr;
6259b9eb518SSomnath Kotur /* L4 source port */
6269b9eb518SSomnath Kotur if (actions->nat.l4.ports.sport)
627bbf33d1dSEdwin Peer req->nat_port =
6289b9eb518SSomnath Kotur actions->nat.l4.ports.sport;
6299b9eb518SSomnath Kotur } else {
6309b9eb518SSomnath Kotur action_flags |=
6319b9eb518SSomnath Kotur CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST;
6329b9eb518SSomnath Kotur /* L3 destination rewrite */
633bbf33d1dSEdwin Peer req->nat_ip_address[0] =
6349b9eb518SSomnath Kotur actions->nat.l3.ipv4.daddr.s_addr;
6359b9eb518SSomnath Kotur /* L4 destination port */
6369b9eb518SSomnath Kotur if (actions->nat.l4.ports.dport)
637bbf33d1dSEdwin Peer req->nat_port =
6389b9eb518SSomnath Kotur actions->nat.l4.ports.dport;
6399b9eb518SSomnath Kotur }
6409b9eb518SSomnath Kotur netdev_dbg(bp->dev,
641bbf33d1dSEdwin Peer "req->nat_ip_address: %pI4 src_xlate: %d req->nat_port: %x\n",
642bbf33d1dSEdwin Peer req->nat_ip_address, actions->nat.src_xlate,
643bbf33d1dSEdwin Peer req->nat_port);
6449b9eb518SSomnath Kotur } else {
6459b9eb518SSomnath Kotur if (actions->nat.src_xlate) {
6469b9eb518SSomnath Kotur action_flags |=
6479b9eb518SSomnath Kotur CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC;
6489b9eb518SSomnath Kotur /* L3 source rewrite */
649bbf33d1dSEdwin Peer memcpy(req->nat_ip_address,
6509b9eb518SSomnath Kotur actions->nat.l3.ipv6.saddr.s6_addr32,
651bbf33d1dSEdwin Peer sizeof(req->nat_ip_address));
6529b9eb518SSomnath Kotur /* L4 source port */
6539b9eb518SSomnath Kotur if (actions->nat.l4.ports.sport)
654bbf33d1dSEdwin Peer req->nat_port =
6559b9eb518SSomnath Kotur actions->nat.l4.ports.sport;
6569b9eb518SSomnath Kotur } else {
6579b9eb518SSomnath Kotur action_flags |=
6589b9eb518SSomnath Kotur CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST;
6599b9eb518SSomnath Kotur /* L3 destination rewrite */
660bbf33d1dSEdwin Peer memcpy(req->nat_ip_address,
6619b9eb518SSomnath Kotur actions->nat.l3.ipv6.daddr.s6_addr32,
662bbf33d1dSEdwin Peer sizeof(req->nat_ip_address));
6639b9eb518SSomnath Kotur /* L4 destination port */
6649b9eb518SSomnath Kotur if (actions->nat.l4.ports.dport)
665bbf33d1dSEdwin Peer req->nat_port =
6669b9eb518SSomnath Kotur actions->nat.l4.ports.dport;
6679b9eb518SSomnath Kotur }
6689b9eb518SSomnath Kotur netdev_dbg(bp->dev,
669bbf33d1dSEdwin Peer "req->nat_ip_address: %pI6 src_xlate: %d req->nat_port: %x\n",
670bbf33d1dSEdwin Peer req->nat_ip_address, actions->nat.src_xlate,
671bbf33d1dSEdwin Peer req->nat_port);
6729b9eb518SSomnath Kotur }
6739b9eb518SSomnath Kotur }
6749b9eb518SSomnath Kotur
6758c95f773SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP ||
6768c95f773SSathya Perla actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) {
677bbf33d1dSEdwin Peer req->tunnel_handle = tunnel_handle;
6788c95f773SSathya Perla flow_flags |= CFA_FLOW_ALLOC_REQ_FLAGS_TUNNEL;
6798c95f773SSathya Perla action_flags |= CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_TUNNEL;
6808c95f773SSathya Perla }
6818c95f773SSathya Perla
682bbf33d1dSEdwin Peer req->ethertype = flow->l2_key.ether_type;
683bbf33d1dSEdwin Peer req->ip_proto = flow->l4_key.ip_proto;
684db1d36a2SSathya Perla
685db1d36a2SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_ETH_ADDRS) {
686bbf33d1dSEdwin Peer memcpy(req->dmac, flow->l2_key.dmac, ETH_ALEN);
687bbf33d1dSEdwin Peer memcpy(req->smac, flow->l2_key.smac, ETH_ALEN);
688db1d36a2SSathya Perla }
689db1d36a2SSathya Perla
690db1d36a2SSathya Perla if (flow->l2_key.num_vlans > 0) {
691db1d36a2SSathya Perla flow_flags |= CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_ONE;
692db1d36a2SSathya Perla /* FW expects the inner_vlan_tci value to be set
693db1d36a2SSathya Perla * in outer_vlan_tci when num_vlans is 1 (which is
694db1d36a2SSathya Perla * always the case in TC.)
695db1d36a2SSathya Perla */
696bbf33d1dSEdwin Peer req->outer_vlan_tci = flow->l2_key.inner_vlan_tci;
697db1d36a2SSathya Perla }
698db1d36a2SSathya Perla
699db1d36a2SSathya Perla /* If all IP and L4 fields are wildcarded then this is an L2 flow */
7007deea450SSunil Challa if (is_wildcard(l3_mask, sizeof(*l3_mask)) &&
701db1d36a2SSathya Perla is_wildcard(&flow->l4_mask, sizeof(flow->l4_mask))) {
702db1d36a2SSathya Perla flow_flags |= CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_L2;
703db1d36a2SSathya Perla } else {
704db1d36a2SSathya Perla flow_flags |= flow->l2_key.ether_type == htons(ETH_P_IP) ?
705db1d36a2SSathya Perla CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV4 :
706db1d36a2SSathya Perla CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6;
707db1d36a2SSathya Perla
708db1d36a2SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_IPV4_ADDRS) {
709bbf33d1dSEdwin Peer req->ip_dst[0] = l3_key->ipv4.daddr.s_addr;
710bbf33d1dSEdwin Peer req->ip_dst_mask_len =
711db1d36a2SSathya Perla inet_mask_len(l3_mask->ipv4.daddr.s_addr);
712bbf33d1dSEdwin Peer req->ip_src[0] = l3_key->ipv4.saddr.s_addr;
713bbf33d1dSEdwin Peer req->ip_src_mask_len =
714db1d36a2SSathya Perla inet_mask_len(l3_mask->ipv4.saddr.s_addr);
715db1d36a2SSathya Perla } else if (flow->flags & BNXT_TC_FLOW_FLAGS_IPV6_ADDRS) {
716bbf33d1dSEdwin Peer memcpy(req->ip_dst, l3_key->ipv6.daddr.s6_addr32,
717bbf33d1dSEdwin Peer sizeof(req->ip_dst));
718bbf33d1dSEdwin Peer req->ip_dst_mask_len =
719db1d36a2SSathya Perla ipv6_mask_len(&l3_mask->ipv6.daddr);
720bbf33d1dSEdwin Peer memcpy(req->ip_src, l3_key->ipv6.saddr.s6_addr32,
721bbf33d1dSEdwin Peer sizeof(req->ip_src));
722bbf33d1dSEdwin Peer req->ip_src_mask_len =
723db1d36a2SSathya Perla ipv6_mask_len(&l3_mask->ipv6.saddr);
724db1d36a2SSathya Perla }
725db1d36a2SSathya Perla }
726db1d36a2SSathya Perla
727db1d36a2SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_PORTS) {
728bbf33d1dSEdwin Peer req->l4_src_port = flow->l4_key.ports.sport;
729bbf33d1dSEdwin Peer req->l4_src_port_mask = flow->l4_mask.ports.sport;
730bbf33d1dSEdwin Peer req->l4_dst_port = flow->l4_key.ports.dport;
731bbf33d1dSEdwin Peer req->l4_dst_port_mask = flow->l4_mask.ports.dport;
732db1d36a2SSathya Perla } else if (flow->flags & BNXT_TC_FLOW_FLAGS_ICMP) {
733db1d36a2SSathya Perla /* l4 ports serve as type/code when ip_proto is ICMP */
734bbf33d1dSEdwin Peer req->l4_src_port = htons(flow->l4_key.icmp.type);
735bbf33d1dSEdwin Peer req->l4_src_port_mask = htons(flow->l4_mask.icmp.type);
736bbf33d1dSEdwin Peer req->l4_dst_port = htons(flow->l4_key.icmp.code);
737bbf33d1dSEdwin Peer req->l4_dst_port_mask = htons(flow->l4_mask.icmp.code);
738db1d36a2SSathya Perla }
739bbf33d1dSEdwin Peer req->flags = cpu_to_le16(flow_flags);
740db1d36a2SSathya Perla
741db1d36a2SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_DROP) {
742db1d36a2SSathya Perla action_flags |= CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_DROP;
743db1d36a2SSathya Perla } else {
744db1d36a2SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) {
745db1d36a2SSathya Perla action_flags |= CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_FWD;
746bbf33d1dSEdwin Peer req->dst_fid = cpu_to_le16(actions->dst_fid);
747db1d36a2SSathya Perla }
748db1d36a2SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_PUSH_VLAN) {
749db1d36a2SSathya Perla action_flags |=
750db1d36a2SSathya Perla CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE;
751bbf33d1dSEdwin Peer req->l2_rewrite_vlan_tpid = actions->push_vlan_tpid;
752bbf33d1dSEdwin Peer req->l2_rewrite_vlan_tci = actions->push_vlan_tci;
753bbf33d1dSEdwin Peer memcpy(&req->l2_rewrite_dmac, &req->dmac, ETH_ALEN);
754bbf33d1dSEdwin Peer memcpy(&req->l2_rewrite_smac, &req->smac, ETH_ALEN);
755db1d36a2SSathya Perla }
756db1d36a2SSathya Perla if (actions->flags & BNXT_TC_ACTION_FLAG_POP_VLAN) {
757db1d36a2SSathya Perla action_flags |=
758db1d36a2SSathya Perla CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE;
759db1d36a2SSathya Perla /* Rewrite config with tpid = 0 implies vlan pop */
760bbf33d1dSEdwin Peer req->l2_rewrite_vlan_tpid = 0;
761bbf33d1dSEdwin Peer memcpy(&req->l2_rewrite_dmac, &req->dmac, ETH_ALEN);
762bbf33d1dSEdwin Peer memcpy(&req->l2_rewrite_smac, &req->smac, ETH_ALEN);
763db1d36a2SSathya Perla }
764db1d36a2SSathya Perla }
765bbf33d1dSEdwin Peer req->action_flags = cpu_to_le16(action_flags);
766db1d36a2SSathya Perla
767bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req);
768bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req);
7695c209fc8SVenkat Duvvuru if (!rc) {
770abd43a13SVenkat Duvvuru /* CFA_FLOW_ALLOC response interpretation:
771abd43a13SVenkat Duvvuru * fw with fw with
772abd43a13SVenkat Duvvuru * 16-bit 64-bit
773abd43a13SVenkat Duvvuru * flow handle flow handle
774abd43a13SVenkat Duvvuru * =========== ===========
775abd43a13SVenkat Duvvuru * flow_handle flow handle flow context id
776abd43a13SVenkat Duvvuru * ext_flow_handle INVALID flow handle
777abd43a13SVenkat Duvvuru * flow_id INVALID flow counter id
778abd43a13SVenkat Duvvuru */
779abd43a13SVenkat Duvvuru flow_node->flow_handle = resp->flow_handle;
780abd43a13SVenkat Duvvuru if (bp->fw_cap & BNXT_FW_CAP_OVS_64BIT_HANDLE) {
781abd43a13SVenkat Duvvuru flow_node->ext_flow_handle = resp->ext_flow_handle;
782abd43a13SVenkat Duvvuru flow_node->flow_id = resp->flow_id;
783abd43a13SVenkat Duvvuru }
7845c209fc8SVenkat Duvvuru }
785bbf33d1dSEdwin Peer hwrm_req_drop(bp, req);
786db1d36a2SSathya Perla return rc;
7872ae7408fSSathya Perla }
7882ae7408fSSathya Perla
hwrm_cfa_decap_filter_alloc(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_l2_key * l2_info,__le32 ref_decap_handle,__le32 * decap_filter_handle)7898c95f773SSathya Perla static int hwrm_cfa_decap_filter_alloc(struct bnxt *bp,
7908c95f773SSathya Perla struct bnxt_tc_flow *flow,
7918c95f773SSathya Perla struct bnxt_tc_l2_key *l2_info,
7928c95f773SSathya Perla __le32 ref_decap_handle,
7938c95f773SSathya Perla __le32 *decap_filter_handle)
7948c95f773SSathya Perla {
7955c209fc8SVenkat Duvvuru struct hwrm_cfa_decap_filter_alloc_output *resp;
796f484f678SSathya Perla struct ip_tunnel_key *tun_key = &flow->tun_key;
797bbf33d1dSEdwin Peer struct hwrm_cfa_decap_filter_alloc_input *req;
798f484f678SSathya Perla u32 enables = 0;
799f484f678SSathya Perla int rc;
800f484f678SSathya Perla
801bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_DECAP_FILTER_ALLOC);
802bbf33d1dSEdwin Peer if (rc)
803bbf33d1dSEdwin Peer goto exit;
804f484f678SSathya Perla
805bbf33d1dSEdwin Peer req->flags = cpu_to_le32(CFA_DECAP_FILTER_ALLOC_REQ_FLAGS_OVS_TUNNEL);
806f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_TUNNEL_TYPE |
807f484f678SSathya Perla CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_IP_PROTOCOL;
808bbf33d1dSEdwin Peer req->tunnel_type = CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN;
809bbf33d1dSEdwin Peer req->ip_protocol = CFA_DECAP_FILTER_ALLOC_REQ_IP_PROTOCOL_UDP;
810f484f678SSathya Perla
811f484f678SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_TUNL_ID) {
812f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_TUNNEL_ID;
813f484f678SSathya Perla /* tunnel_id is wrongly defined in hsi defn. as __le32 */
814bbf33d1dSEdwin Peer req->tunnel_id = tunnel_id_to_key32(tun_key->tun_id);
815f484f678SSathya Perla }
816f484f678SSathya Perla
817f484f678SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_TUNL_ETH_ADDRS) {
818c8fb7b82SSunil Challa enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_DST_MACADDR;
819bbf33d1dSEdwin Peer ether_addr_copy(req->dst_macaddr, l2_info->dmac);
820f484f678SSathya Perla }
821f484f678SSathya Perla if (l2_info->num_vlans) {
822f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_T_IVLAN_VID;
823bbf33d1dSEdwin Peer req->t_ivlan_vid = l2_info->inner_vlan_tci;
824f484f678SSathya Perla }
825f484f678SSathya Perla
826f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_ETHERTYPE;
827bbf33d1dSEdwin Peer req->ethertype = htons(ETH_P_IP);
828f484f678SSathya Perla
829f484f678SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_TUNL_IPV4_ADDRS) {
830f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_SRC_IPADDR |
831f484f678SSathya Perla CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_DST_IPADDR |
832f484f678SSathya Perla CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_IPADDR_TYPE;
833bbf33d1dSEdwin Peer req->ip_addr_type =
834bbf33d1dSEdwin Peer CFA_DECAP_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV4;
835bbf33d1dSEdwin Peer req->dst_ipaddr[0] = tun_key->u.ipv4.dst;
836bbf33d1dSEdwin Peer req->src_ipaddr[0] = tun_key->u.ipv4.src;
837f484f678SSathya Perla }
838f484f678SSathya Perla
839f484f678SSathya Perla if (flow->flags & BNXT_TC_FLOW_FLAGS_TUNL_PORTS) {
840f484f678SSathya Perla enables |= CFA_DECAP_FILTER_ALLOC_REQ_ENABLES_DST_PORT;
841bbf33d1dSEdwin Peer req->dst_port = tun_key->tp_dst;
842f484f678SSathya Perla }
843f484f678SSathya Perla
844f484f678SSathya Perla /* Eventhough the decap_handle returned by hwrm_cfa_decap_filter_alloc
845f484f678SSathya Perla * is defined as __le32, l2_ctxt_ref_id is defined in HSI as __le16.
846f484f678SSathya Perla */
847bbf33d1dSEdwin Peer req->l2_ctxt_ref_id = (__force __le16)ref_decap_handle;
848bbf33d1dSEdwin Peer req->enables = cpu_to_le32(enables);
849f484f678SSathya Perla
850bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req);
851bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req);
852bbf33d1dSEdwin Peer if (!rc)
853f484f678SSathya Perla *decap_filter_handle = resp->decap_filter_id;
854bbf33d1dSEdwin Peer hwrm_req_drop(bp, req);
855bbf33d1dSEdwin Peer exit:
856bbf33d1dSEdwin Peer if (rc)
8579a005c38SJonathan Lemon netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
858f484f678SSathya Perla
859f484f678SSathya Perla return rc;
8608c95f773SSathya Perla }
8618c95f773SSathya Perla
hwrm_cfa_decap_filter_free(struct bnxt * bp,__le32 decap_filter_handle)8628c95f773SSathya Perla static int hwrm_cfa_decap_filter_free(struct bnxt *bp,
8638c95f773SSathya Perla __le32 decap_filter_handle)
8648c95f773SSathya Perla {
865bbf33d1dSEdwin Peer struct hwrm_cfa_decap_filter_free_input *req;
866f484f678SSathya Perla int rc;
867f484f678SSathya Perla
868bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_DECAP_FILTER_FREE);
869bbf33d1dSEdwin Peer if (!rc) {
870bbf33d1dSEdwin Peer req->decap_filter_id = decap_filter_handle;
871bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req);
872bbf33d1dSEdwin Peer }
873f484f678SSathya Perla if (rc)
8749a005c38SJonathan Lemon netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
8756ae777eaSVenkat Duvvuru
876f484f678SSathya Perla return rc;
8778c95f773SSathya Perla }
8788c95f773SSathya Perla
hwrm_cfa_encap_record_alloc(struct bnxt * bp,struct ip_tunnel_key * encap_key,struct bnxt_tc_l2_key * l2_info,__le32 * encap_record_handle)8798c95f773SSathya Perla static int hwrm_cfa_encap_record_alloc(struct bnxt *bp,
8808c95f773SSathya Perla struct ip_tunnel_key *encap_key,
8818c95f773SSathya Perla struct bnxt_tc_l2_key *l2_info,
8828c95f773SSathya Perla __le32 *encap_record_handle)
8838c95f773SSathya Perla {
8845c209fc8SVenkat Duvvuru struct hwrm_cfa_encap_record_alloc_output *resp;
885bbf33d1dSEdwin Peer struct hwrm_cfa_encap_record_alloc_input *req;
886bbf33d1dSEdwin Peer struct hwrm_cfa_encap_data_vxlan *encap;
887bbf33d1dSEdwin Peer struct hwrm_vxlan_ipv4_hdr *encap_ipv4;
888f484f678SSathya Perla int rc;
889f484f678SSathya Perla
890bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_ENCAP_RECORD_ALLOC);
891bbf33d1dSEdwin Peer if (rc)
892bbf33d1dSEdwin Peer goto exit;
893f484f678SSathya Perla
894bbf33d1dSEdwin Peer encap = (struct hwrm_cfa_encap_data_vxlan *)&req->encap_data;
895bbf33d1dSEdwin Peer req->encap_type = CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN;
896f484f678SSathya Perla ether_addr_copy(encap->dst_mac_addr, l2_info->dmac);
897f484f678SSathya Perla ether_addr_copy(encap->src_mac_addr, l2_info->smac);
898f484f678SSathya Perla if (l2_info->num_vlans) {
899f484f678SSathya Perla encap->num_vlan_tags = l2_info->num_vlans;
900f484f678SSathya Perla encap->ovlan_tci = l2_info->inner_vlan_tci;
901f484f678SSathya Perla encap->ovlan_tpid = l2_info->inner_vlan_tpid;
902f484f678SSathya Perla }
903f484f678SSathya Perla
904bbf33d1dSEdwin Peer encap_ipv4 = (struct hwrm_vxlan_ipv4_hdr *)encap->l3;
905f484f678SSathya Perla encap_ipv4->ver_hlen = 4 << VXLAN_IPV4_HDR_VER_HLEN_VERSION_SFT;
906f484f678SSathya Perla encap_ipv4->ver_hlen |= 5 << VXLAN_IPV4_HDR_VER_HLEN_HEADER_LENGTH_SFT;
907f484f678SSathya Perla encap_ipv4->ttl = encap_key->ttl;
908f484f678SSathya Perla
909f484f678SSathya Perla encap_ipv4->dest_ip_addr = encap_key->u.ipv4.dst;
910f484f678SSathya Perla encap_ipv4->src_ip_addr = encap_key->u.ipv4.src;
911f484f678SSathya Perla encap_ipv4->protocol = IPPROTO_UDP;
912f484f678SSathya Perla
913f484f678SSathya Perla encap->dst_port = encap_key->tp_dst;
914f484f678SSathya Perla encap->vni = tunnel_id_to_key32(encap_key->tun_id);
915f484f678SSathya Perla
916bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req);
917bbf33d1dSEdwin Peer rc = hwrm_req_send_silent(bp, req);
918bbf33d1dSEdwin Peer if (!rc)
919f484f678SSathya Perla *encap_record_handle = resp->encap_record_id;
920bbf33d1dSEdwin Peer hwrm_req_drop(bp, req);
921bbf33d1dSEdwin Peer exit:
922bbf33d1dSEdwin Peer if (rc)
9239a005c38SJonathan Lemon netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
924f484f678SSathya Perla
925f484f678SSathya Perla return rc;
9268c95f773SSathya Perla }
9278c95f773SSathya Perla
hwrm_cfa_encap_record_free(struct bnxt * bp,__le32 encap_record_handle)9288c95f773SSathya Perla static int hwrm_cfa_encap_record_free(struct bnxt *bp,
9298c95f773SSathya Perla __le32 encap_record_handle)
9308c95f773SSathya Perla {
931bbf33d1dSEdwin Peer struct hwrm_cfa_encap_record_free_input *req;
932f484f678SSathya Perla int rc;
933f484f678SSathya Perla
934bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_ENCAP_RECORD_FREE);
935bbf33d1dSEdwin Peer if (!rc) {
936bbf33d1dSEdwin Peer req->encap_record_id = encap_record_handle;
937bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req);
938bbf33d1dSEdwin Peer }
939f484f678SSathya Perla if (rc)
9409a005c38SJonathan Lemon netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
9416ae777eaSVenkat Duvvuru
942f484f678SSathya Perla return rc;
9438c95f773SSathya Perla }
9448c95f773SSathya Perla
bnxt_tc_put_l2_node(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node)9452ae7408fSSathya Perla static int bnxt_tc_put_l2_node(struct bnxt *bp,
9462ae7408fSSathya Perla struct bnxt_tc_flow_node *flow_node)
9472ae7408fSSathya Perla {
9482ae7408fSSathya Perla struct bnxt_tc_l2_node *l2_node = flow_node->l2_node;
949cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
9502ae7408fSSathya Perla int rc;
9512ae7408fSSathya Perla
9522ae7408fSSathya Perla /* remove flow_node from the L2 shared flow list */
9532ae7408fSSathya Perla list_del(&flow_node->l2_list_node);
9542ae7408fSSathya Perla if (--l2_node->refcount == 0) {
9552ae7408fSSathya Perla rc = rhashtable_remove_fast(&tc_info->l2_table, &l2_node->node,
9562ae7408fSSathya Perla tc_info->l2_ht_params);
9572ae7408fSSathya Perla if (rc)
9582ae7408fSSathya Perla netdev_err(bp->dev,
9599a005c38SJonathan Lemon "Error: %s: rhashtable_remove_fast: %d\n",
9602ae7408fSSathya Perla __func__, rc);
9612ae7408fSSathya Perla kfree_rcu(l2_node, rcu);
9622ae7408fSSathya Perla }
9632ae7408fSSathya Perla return 0;
9642ae7408fSSathya Perla }
9652ae7408fSSathya Perla
9662ae7408fSSathya Perla static struct bnxt_tc_l2_node *
bnxt_tc_get_l2_node(struct bnxt * bp,struct rhashtable * l2_table,struct rhashtable_params ht_params,struct bnxt_tc_l2_key * l2_key)9672ae7408fSSathya Perla bnxt_tc_get_l2_node(struct bnxt *bp, struct rhashtable *l2_table,
9682ae7408fSSathya Perla struct rhashtable_params ht_params,
9692ae7408fSSathya Perla struct bnxt_tc_l2_key *l2_key)
9702ae7408fSSathya Perla {
9712ae7408fSSathya Perla struct bnxt_tc_l2_node *l2_node;
9722ae7408fSSathya Perla int rc;
9732ae7408fSSathya Perla
9742ae7408fSSathya Perla l2_node = rhashtable_lookup_fast(l2_table, l2_key, ht_params);
9752ae7408fSSathya Perla if (!l2_node) {
9762ae7408fSSathya Perla l2_node = kzalloc(sizeof(*l2_node), GFP_KERNEL);
9772ae7408fSSathya Perla if (!l2_node) {
9782ae7408fSSathya Perla rc = -ENOMEM;
9792ae7408fSSathya Perla return NULL;
9802ae7408fSSathya Perla }
9812ae7408fSSathya Perla
9822ae7408fSSathya Perla l2_node->key = *l2_key;
9832ae7408fSSathya Perla rc = rhashtable_insert_fast(l2_table, &l2_node->node,
9842ae7408fSSathya Perla ht_params);
9852ae7408fSSathya Perla if (rc) {
9868c95f773SSathya Perla kfree_rcu(l2_node, rcu);
9872ae7408fSSathya Perla netdev_err(bp->dev,
9889a005c38SJonathan Lemon "Error: %s: rhashtable_insert_fast: %d\n",
9892ae7408fSSathya Perla __func__, rc);
9902ae7408fSSathya Perla return NULL;
9912ae7408fSSathya Perla }
9922ae7408fSSathya Perla INIT_LIST_HEAD(&l2_node->common_l2_flows);
9932ae7408fSSathya Perla }
9942ae7408fSSathya Perla return l2_node;
9952ae7408fSSathya Perla }
9962ae7408fSSathya Perla
9972ae7408fSSathya Perla /* Get the ref_flow_handle for a flow by checking if there are any other
9982ae7408fSSathya Perla * flows that share the same L2 key as this flow.
9992ae7408fSSathya Perla */
10002ae7408fSSathya Perla static int
bnxt_tc_get_ref_flow_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_flow_node * flow_node,__le16 * ref_flow_handle)10012ae7408fSSathya Perla bnxt_tc_get_ref_flow_handle(struct bnxt *bp, struct bnxt_tc_flow *flow,
10022ae7408fSSathya Perla struct bnxt_tc_flow_node *flow_node,
10032ae7408fSSathya Perla __le16 *ref_flow_handle)
10042ae7408fSSathya Perla {
1005cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
10062ae7408fSSathya Perla struct bnxt_tc_flow_node *ref_flow_node;
10072ae7408fSSathya Perla struct bnxt_tc_l2_node *l2_node;
10082ae7408fSSathya Perla
10092ae7408fSSathya Perla l2_node = bnxt_tc_get_l2_node(bp, &tc_info->l2_table,
10102ae7408fSSathya Perla tc_info->l2_ht_params,
10112ae7408fSSathya Perla &flow->l2_key);
10122ae7408fSSathya Perla if (!l2_node)
10132ae7408fSSathya Perla return -1;
10142ae7408fSSathya Perla
10152ae7408fSSathya Perla /* If any other flow is using this l2_node, use it's flow_handle
10162ae7408fSSathya Perla * as the ref_flow_handle
10172ae7408fSSathya Perla */
10182ae7408fSSathya Perla if (l2_node->refcount > 0) {
10192ae7408fSSathya Perla ref_flow_node = list_first_entry(&l2_node->common_l2_flows,
10202ae7408fSSathya Perla struct bnxt_tc_flow_node,
10212ae7408fSSathya Perla l2_list_node);
10222ae7408fSSathya Perla *ref_flow_handle = ref_flow_node->flow_handle;
10232ae7408fSSathya Perla } else {
10242ae7408fSSathya Perla *ref_flow_handle = cpu_to_le16(0xffff);
10252ae7408fSSathya Perla }
10262ae7408fSSathya Perla
10272ae7408fSSathya Perla /* Insert the l2_node into the flow_node so that subsequent flows
10282ae7408fSSathya Perla * with a matching l2 key can use the flow_handle of this flow
10292ae7408fSSathya Perla * as their ref_flow_handle
10302ae7408fSSathya Perla */
10312ae7408fSSathya Perla flow_node->l2_node = l2_node;
10322ae7408fSSathya Perla list_add(&flow_node->l2_list_node, &l2_node->common_l2_flows);
10332ae7408fSSathya Perla l2_node->refcount++;
10342ae7408fSSathya Perla return 0;
10352ae7408fSSathya Perla }
10362ae7408fSSathya Perla
10372ae7408fSSathya Perla /* After the flow parsing is done, this routine is used for checking
10382ae7408fSSathya Perla * if there are any aspects of the flow that prevent it from being
10392ae7408fSSathya Perla * offloaded.
10402ae7408fSSathya Perla */
bnxt_tc_can_offload(struct bnxt * bp,struct bnxt_tc_flow * flow)10412ae7408fSSathya Perla static bool bnxt_tc_can_offload(struct bnxt *bp, struct bnxt_tc_flow *flow)
10422ae7408fSSathya Perla {
10432ae7408fSSathya Perla /* If L4 ports are specified then ip_proto must be TCP or UDP */
10442ae7408fSSathya Perla if ((flow->flags & BNXT_TC_FLOW_FLAGS_PORTS) &&
10452ae7408fSSathya Perla (flow->l4_key.ip_proto != IPPROTO_TCP &&
10462ae7408fSSathya Perla flow->l4_key.ip_proto != IPPROTO_UDP)) {
10479a005c38SJonathan Lemon netdev_info(bp->dev, "Cannot offload non-TCP/UDP (%d) ports\n",
10482ae7408fSSathya Perla flow->l4_key.ip_proto);
10492ae7408fSSathya Perla return false;
10502ae7408fSSathya Perla }
10512ae7408fSSathya Perla
1052e85a9be9SAndy Gospodarek /* Currently source/dest MAC cannot be partial wildcard */
1053e85a9be9SAndy Gospodarek if (bits_set(&flow->l2_key.smac, sizeof(flow->l2_key.smac)) &&
1054e85a9be9SAndy Gospodarek !is_exactmatch(flow->l2_mask.smac, sizeof(flow->l2_mask.smac))) {
1055e85a9be9SAndy Gospodarek netdev_info(bp->dev, "Wildcard match unsupported for Source MAC\n");
1056e85a9be9SAndy Gospodarek return false;
1057e85a9be9SAndy Gospodarek }
1058e85a9be9SAndy Gospodarek if (bits_set(&flow->l2_key.dmac, sizeof(flow->l2_key.dmac)) &&
1059e85a9be9SAndy Gospodarek !is_exactmatch(&flow->l2_mask.dmac, sizeof(flow->l2_mask.dmac))) {
1060e85a9be9SAndy Gospodarek netdev_info(bp->dev, "Wildcard match unsupported for Dest MAC\n");
1061e85a9be9SAndy Gospodarek return false;
1062e85a9be9SAndy Gospodarek }
1063e85a9be9SAndy Gospodarek
1064e85a9be9SAndy Gospodarek /* Currently VLAN fields cannot be partial wildcard */
1065e85a9be9SAndy Gospodarek if (bits_set(&flow->l2_key.inner_vlan_tci,
1066e85a9be9SAndy Gospodarek sizeof(flow->l2_key.inner_vlan_tci)) &&
1067e32d4e60SVenkat Duvvuru !is_vlan_tci_allowed(flow->l2_mask.inner_vlan_tci,
1068e32d4e60SVenkat Duvvuru flow->l2_key.inner_vlan_tci)) {
1069e32d4e60SVenkat Duvvuru netdev_info(bp->dev, "Unsupported VLAN TCI\n");
1070e85a9be9SAndy Gospodarek return false;
1071e85a9be9SAndy Gospodarek }
1072e85a9be9SAndy Gospodarek if (bits_set(&flow->l2_key.inner_vlan_tpid,
1073e85a9be9SAndy Gospodarek sizeof(flow->l2_key.inner_vlan_tpid)) &&
1074e85a9be9SAndy Gospodarek !is_exactmatch(&flow->l2_mask.inner_vlan_tpid,
1075e85a9be9SAndy Gospodarek sizeof(flow->l2_mask.inner_vlan_tpid))) {
1076e85a9be9SAndy Gospodarek netdev_info(bp->dev, "Wildcard match unsupported for VLAN TPID\n");
1077e85a9be9SAndy Gospodarek return false;
1078e85a9be9SAndy Gospodarek }
1079e85a9be9SAndy Gospodarek
1080e85a9be9SAndy Gospodarek /* Currently Ethertype must be set */
1081e85a9be9SAndy Gospodarek if (!is_exactmatch(&flow->l2_mask.ether_type,
1082e85a9be9SAndy Gospodarek sizeof(flow->l2_mask.ether_type))) {
1083e85a9be9SAndy Gospodarek netdev_info(bp->dev, "Wildcard match unsupported for Ethertype\n");
1084e85a9be9SAndy Gospodarek return false;
1085e85a9be9SAndy Gospodarek }
1086e85a9be9SAndy Gospodarek
10872ae7408fSSathya Perla return true;
10882ae7408fSSathya Perla }
10892ae7408fSSathya Perla
10908c95f773SSathya Perla /* Returns the final refcount of the node on success
10918c95f773SSathya Perla * or a -ve error code on failure
10928c95f773SSathya Perla */
bnxt_tc_put_tunnel_node(struct bnxt * bp,struct rhashtable * tunnel_table,struct rhashtable_params * ht_params,struct bnxt_tc_tunnel_node * tunnel_node)10938c95f773SSathya Perla static int bnxt_tc_put_tunnel_node(struct bnxt *bp,
10948c95f773SSathya Perla struct rhashtable *tunnel_table,
10958c95f773SSathya Perla struct rhashtable_params *ht_params,
10968c95f773SSathya Perla struct bnxt_tc_tunnel_node *tunnel_node)
10978c95f773SSathya Perla {
10988c95f773SSathya Perla int rc;
10998c95f773SSathya Perla
11008c95f773SSathya Perla if (--tunnel_node->refcount == 0) {
11018c95f773SSathya Perla rc = rhashtable_remove_fast(tunnel_table, &tunnel_node->node,
11028c95f773SSathya Perla *ht_params);
11038c95f773SSathya Perla if (rc) {
11049a005c38SJonathan Lemon netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
11058c95f773SSathya Perla rc = -1;
11068c95f773SSathya Perla }
11078c95f773SSathya Perla kfree_rcu(tunnel_node, rcu);
11088c95f773SSathya Perla return rc;
11098c95f773SSathya Perla } else {
11108c95f773SSathya Perla return tunnel_node->refcount;
11118c95f773SSathya Perla }
11128c95f773SSathya Perla }
11138c95f773SSathya Perla
11148c95f773SSathya Perla /* Get (or add) either encap or decap tunnel node from/to the supplied
11158c95f773SSathya Perla * hash table.
11168c95f773SSathya Perla */
11178c95f773SSathya Perla static struct bnxt_tc_tunnel_node *
bnxt_tc_get_tunnel_node(struct bnxt * bp,struct rhashtable * tunnel_table,struct rhashtable_params * ht_params,struct ip_tunnel_key * tun_key)11188c95f773SSathya Perla bnxt_tc_get_tunnel_node(struct bnxt *bp, struct rhashtable *tunnel_table,
11198c95f773SSathya Perla struct rhashtable_params *ht_params,
11208c95f773SSathya Perla struct ip_tunnel_key *tun_key)
11218c95f773SSathya Perla {
11228c95f773SSathya Perla struct bnxt_tc_tunnel_node *tunnel_node;
11238c95f773SSathya Perla int rc;
11248c95f773SSathya Perla
11258c95f773SSathya Perla tunnel_node = rhashtable_lookup_fast(tunnel_table, tun_key, *ht_params);
11268c95f773SSathya Perla if (!tunnel_node) {
11278c95f773SSathya Perla tunnel_node = kzalloc(sizeof(*tunnel_node), GFP_KERNEL);
11288c95f773SSathya Perla if (!tunnel_node) {
11298c95f773SSathya Perla rc = -ENOMEM;
11308c95f773SSathya Perla goto err;
11318c95f773SSathya Perla }
11328c95f773SSathya Perla
11338c95f773SSathya Perla tunnel_node->key = *tun_key;
11348c95f773SSathya Perla tunnel_node->tunnel_handle = INVALID_TUNNEL_HANDLE;
11358c95f773SSathya Perla rc = rhashtable_insert_fast(tunnel_table, &tunnel_node->node,
11368c95f773SSathya Perla *ht_params);
11378c95f773SSathya Perla if (rc) {
11388c95f773SSathya Perla kfree_rcu(tunnel_node, rcu);
11398c95f773SSathya Perla goto err;
11408c95f773SSathya Perla }
11418c95f773SSathya Perla }
11428c95f773SSathya Perla tunnel_node->refcount++;
11438c95f773SSathya Perla return tunnel_node;
11448c95f773SSathya Perla err:
11459a005c38SJonathan Lemon netdev_info(bp->dev, "error rc=%d\n", rc);
11468c95f773SSathya Perla return NULL;
11478c95f773SSathya Perla }
11488c95f773SSathya Perla
bnxt_tc_get_ref_decap_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_l2_key * l2_key,struct bnxt_tc_flow_node * flow_node,__le32 * ref_decap_handle)11498c95f773SSathya Perla static int bnxt_tc_get_ref_decap_handle(struct bnxt *bp,
11508c95f773SSathya Perla struct bnxt_tc_flow *flow,
11518c95f773SSathya Perla struct bnxt_tc_l2_key *l2_key,
11528c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node,
11538c95f773SSathya Perla __le32 *ref_decap_handle)
11548c95f773SSathya Perla {
1155cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
11568c95f773SSathya Perla struct bnxt_tc_flow_node *ref_flow_node;
11578c95f773SSathya Perla struct bnxt_tc_l2_node *decap_l2_node;
11588c95f773SSathya Perla
11598c95f773SSathya Perla decap_l2_node = bnxt_tc_get_l2_node(bp, &tc_info->decap_l2_table,
11608c95f773SSathya Perla tc_info->decap_l2_ht_params,
11618c95f773SSathya Perla l2_key);
11628c95f773SSathya Perla if (!decap_l2_node)
11638c95f773SSathya Perla return -1;
11648c95f773SSathya Perla
11658c95f773SSathya Perla /* If any other flow is using this decap_l2_node, use it's decap_handle
11668c95f773SSathya Perla * as the ref_decap_handle
11678c95f773SSathya Perla */
11688c95f773SSathya Perla if (decap_l2_node->refcount > 0) {
11698c95f773SSathya Perla ref_flow_node =
11708c95f773SSathya Perla list_first_entry(&decap_l2_node->common_l2_flows,
11718c95f773SSathya Perla struct bnxt_tc_flow_node,
11728c95f773SSathya Perla decap_l2_list_node);
11738c95f773SSathya Perla *ref_decap_handle = ref_flow_node->decap_node->tunnel_handle;
11748c95f773SSathya Perla } else {
11758c95f773SSathya Perla *ref_decap_handle = INVALID_TUNNEL_HANDLE;
11768c95f773SSathya Perla }
11778c95f773SSathya Perla
11788c95f773SSathya Perla /* Insert the l2_node into the flow_node so that subsequent flows
11798c95f773SSathya Perla * with a matching decap l2 key can use the decap_filter_handle of
11808c95f773SSathya Perla * this flow as their ref_decap_handle
11818c95f773SSathya Perla */
11828c95f773SSathya Perla flow_node->decap_l2_node = decap_l2_node;
11838c95f773SSathya Perla list_add(&flow_node->decap_l2_list_node,
11848c95f773SSathya Perla &decap_l2_node->common_l2_flows);
11858c95f773SSathya Perla decap_l2_node->refcount++;
11868c95f773SSathya Perla return 0;
11878c95f773SSathya Perla }
11888c95f773SSathya Perla
bnxt_tc_put_decap_l2_node(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node)11898c95f773SSathya Perla static void bnxt_tc_put_decap_l2_node(struct bnxt *bp,
11908c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node)
11918c95f773SSathya Perla {
11928c95f773SSathya Perla struct bnxt_tc_l2_node *decap_l2_node = flow_node->decap_l2_node;
1193cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
11948c95f773SSathya Perla int rc;
11958c95f773SSathya Perla
11968c95f773SSathya Perla /* remove flow_node from the decap L2 sharing flow list */
11978c95f773SSathya Perla list_del(&flow_node->decap_l2_list_node);
11988c95f773SSathya Perla if (--decap_l2_node->refcount == 0) {
11998c95f773SSathya Perla rc = rhashtable_remove_fast(&tc_info->decap_l2_table,
12008c95f773SSathya Perla &decap_l2_node->node,
12018c95f773SSathya Perla tc_info->decap_l2_ht_params);
12028c95f773SSathya Perla if (rc)
12039a005c38SJonathan Lemon netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
12048c95f773SSathya Perla kfree_rcu(decap_l2_node, rcu);
12058c95f773SSathya Perla }
12068c95f773SSathya Perla }
12078c95f773SSathya Perla
bnxt_tc_put_decap_handle(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node)12088c95f773SSathya Perla static void bnxt_tc_put_decap_handle(struct bnxt *bp,
12098c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node)
12108c95f773SSathya Perla {
12118c95f773SSathya Perla __le32 decap_handle = flow_node->decap_node->tunnel_handle;
1212cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
12138c95f773SSathya Perla int rc;
12148c95f773SSathya Perla
12158c95f773SSathya Perla if (flow_node->decap_l2_node)
12168c95f773SSathya Perla bnxt_tc_put_decap_l2_node(bp, flow_node);
12178c95f773SSathya Perla
12188c95f773SSathya Perla rc = bnxt_tc_put_tunnel_node(bp, &tc_info->decap_table,
12198c95f773SSathya Perla &tc_info->decap_ht_params,
12208c95f773SSathya Perla flow_node->decap_node);
12218c95f773SSathya Perla if (!rc && decap_handle != INVALID_TUNNEL_HANDLE)
12228c95f773SSathya Perla hwrm_cfa_decap_filter_free(bp, decap_handle);
12238c95f773SSathya Perla }
12248c95f773SSathya Perla
bnxt_tc_resolve_tunnel_hdrs(struct bnxt * bp,struct ip_tunnel_key * tun_key,struct bnxt_tc_l2_key * l2_info)12258c95f773SSathya Perla static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
12268c95f773SSathya Perla struct ip_tunnel_key *tun_key,
1227e9ecc731SSathya Perla struct bnxt_tc_l2_key *l2_info)
12288c95f773SSathya Perla {
1229952c5719SMichael Chan #ifdef CONFIG_INET
1230e9ecc731SSathya Perla struct net_device *real_dst_dev = bp->dev;
12318c95f773SSathya Perla struct flowi4 flow = { {0} };
12328c95f773SSathya Perla struct net_device *dst_dev;
12338c95f773SSathya Perla struct neighbour *nbr;
12348c95f773SSathya Perla struct rtable *rt;
12358c95f773SSathya Perla int rc;
12368c95f773SSathya Perla
12378c95f773SSathya Perla flow.flowi4_proto = IPPROTO_UDP;
12388c95f773SSathya Perla flow.fl4_dport = tun_key->tp_dst;
12398c95f773SSathya Perla flow.daddr = tun_key->u.ipv4.dst;
12408c95f773SSathya Perla
12418c95f773SSathya Perla rt = ip_route_output_key(dev_net(real_dst_dev), &flow);
12428c95f773SSathya Perla if (IS_ERR(rt)) {
12439a005c38SJonathan Lemon netdev_info(bp->dev, "no route to %pI4b\n", &flow.daddr);
12448c95f773SSathya Perla return -EOPNOTSUPP;
12458c95f773SSathya Perla }
12468c95f773SSathya Perla
12478c95f773SSathya Perla /* The route must either point to the real_dst_dev or a dst_dev that
12488c95f773SSathya Perla * uses the real_dst_dev.
12498c95f773SSathya Perla */
12508c95f773SSathya Perla dst_dev = rt->dst.dev;
12518c95f773SSathya Perla if (is_vlan_dev(dst_dev)) {
1252952c5719SMichael Chan #if IS_ENABLED(CONFIG_VLAN_8021Q)
12538c95f773SSathya Perla struct vlan_dev_priv *vlan = vlan_dev_priv(dst_dev);
12548c95f773SSathya Perla
12558c95f773SSathya Perla if (vlan->real_dev != real_dst_dev) {
12568c95f773SSathya Perla netdev_info(bp->dev,
12579a005c38SJonathan Lemon "dst_dev(%s) doesn't use PF-if(%s)\n",
12588c95f773SSathya Perla netdev_name(dst_dev),
12598c95f773SSathya Perla netdev_name(real_dst_dev));
12608c95f773SSathya Perla rc = -EOPNOTSUPP;
12618c95f773SSathya Perla goto put_rt;
12628c95f773SSathya Perla }
12638c95f773SSathya Perla l2_info->inner_vlan_tci = htons(vlan->vlan_id);
12648c95f773SSathya Perla l2_info->inner_vlan_tpid = vlan->vlan_proto;
12658c95f773SSathya Perla l2_info->num_vlans = 1;
1266952c5719SMichael Chan #endif
12678c95f773SSathya Perla } else if (dst_dev != real_dst_dev) {
12688c95f773SSathya Perla netdev_info(bp->dev,
12699a005c38SJonathan Lemon "dst_dev(%s) for %pI4b is not PF-if(%s)\n",
12708c95f773SSathya Perla netdev_name(dst_dev), &flow.daddr,
12718c95f773SSathya Perla netdev_name(real_dst_dev));
12728c95f773SSathya Perla rc = -EOPNOTSUPP;
12738c95f773SSathya Perla goto put_rt;
12748c95f773SSathya Perla }
12758c95f773SSathya Perla
12768c95f773SSathya Perla nbr = dst_neigh_lookup(&rt->dst, &flow.daddr);
12778c95f773SSathya Perla if (!nbr) {
12789a005c38SJonathan Lemon netdev_info(bp->dev, "can't lookup neighbor for %pI4b\n",
12798c95f773SSathya Perla &flow.daddr);
12808c95f773SSathya Perla rc = -EOPNOTSUPP;
12818c95f773SSathya Perla goto put_rt;
12828c95f773SSathya Perla }
12838c95f773SSathya Perla
12848c95f773SSathya Perla tun_key->u.ipv4.src = flow.saddr;
12858c95f773SSathya Perla tun_key->ttl = ip4_dst_hoplimit(&rt->dst);
12868c95f773SSathya Perla neigh_ha_snapshot(l2_info->dmac, nbr, dst_dev);
12878c95f773SSathya Perla ether_addr_copy(l2_info->smac, dst_dev->dev_addr);
12888c95f773SSathya Perla neigh_release(nbr);
12898c95f773SSathya Perla ip_rt_put(rt);
12908c95f773SSathya Perla
12918c95f773SSathya Perla return 0;
12928c95f773SSathya Perla put_rt:
12938c95f773SSathya Perla ip_rt_put(rt);
12948c95f773SSathya Perla return rc;
1295952c5719SMichael Chan #else
1296952c5719SMichael Chan return -EOPNOTSUPP;
1297952c5719SMichael Chan #endif
12988c95f773SSathya Perla }
12998c95f773SSathya Perla
bnxt_tc_get_decap_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_flow_node * flow_node,__le32 * decap_filter_handle)13008c95f773SSathya Perla static int bnxt_tc_get_decap_handle(struct bnxt *bp, struct bnxt_tc_flow *flow,
13018c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node,
13028c95f773SSathya Perla __le32 *decap_filter_handle)
13038c95f773SSathya Perla {
13048c95f773SSathya Perla struct ip_tunnel_key *decap_key = &flow->tun_key;
1305cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
13068c95f773SSathya Perla struct bnxt_tc_l2_key l2_info = { {0} };
13078c95f773SSathya Perla struct bnxt_tc_tunnel_node *decap_node;
13088c95f773SSathya Perla struct ip_tunnel_key tun_key = { 0 };
13098c95f773SSathya Perla struct bnxt_tc_l2_key *decap_l2_info;
13108c95f773SSathya Perla __le32 ref_decap_handle;
13118c95f773SSathya Perla int rc;
13128c95f773SSathya Perla
13138c95f773SSathya Perla /* Check if there's another flow using the same tunnel decap.
13148c95f773SSathya Perla * If not, add this tunnel to the table and resolve the other
1315479ca3bfSSriharsha Basavapatna * tunnel header fileds. Ignore src_port in the tunnel_key,
1316479ca3bfSSriharsha Basavapatna * since it is not required for decap filters.
13178c95f773SSathya Perla */
1318479ca3bfSSriharsha Basavapatna decap_key->tp_src = 0;
13198c95f773SSathya Perla decap_node = bnxt_tc_get_tunnel_node(bp, &tc_info->decap_table,
13208c95f773SSathya Perla &tc_info->decap_ht_params,
13218c95f773SSathya Perla decap_key);
13228c95f773SSathya Perla if (!decap_node)
13238c95f773SSathya Perla return -ENOMEM;
13248c95f773SSathya Perla
13258c95f773SSathya Perla flow_node->decap_node = decap_node;
13268c95f773SSathya Perla
13278c95f773SSathya Perla if (decap_node->tunnel_handle != INVALID_TUNNEL_HANDLE)
13288c95f773SSathya Perla goto done;
13298c95f773SSathya Perla
13308c95f773SSathya Perla /* Resolve the L2 fields for tunnel decap
13318c95f773SSathya Perla * Resolve the route for remote vtep (saddr) of the decap key
13328c95f773SSathya Perla * Find it's next-hop mac addrs
13338c95f773SSathya Perla */
13348c95f773SSathya Perla tun_key.u.ipv4.dst = flow->tun_key.u.ipv4.src;
13358c95f773SSathya Perla tun_key.tp_dst = flow->tun_key.tp_dst;
1336e9ecc731SSathya Perla rc = bnxt_tc_resolve_tunnel_hdrs(bp, &tun_key, &l2_info);
13378c95f773SSathya Perla if (rc)
13388c95f773SSathya Perla goto put_decap;
13398c95f773SSathya Perla
13408c95f773SSathya Perla decap_l2_info = &decap_node->l2_info;
1341c8fb7b82SSunil Challa /* decap smac is wildcarded */
13428c95f773SSathya Perla ether_addr_copy(decap_l2_info->dmac, l2_info.smac);
13438c95f773SSathya Perla if (l2_info.num_vlans) {
13448c95f773SSathya Perla decap_l2_info->num_vlans = l2_info.num_vlans;
13458c95f773SSathya Perla decap_l2_info->inner_vlan_tpid = l2_info.inner_vlan_tpid;
13468c95f773SSathya Perla decap_l2_info->inner_vlan_tci = l2_info.inner_vlan_tci;
13478c95f773SSathya Perla }
13488c95f773SSathya Perla flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_ETH_ADDRS;
13498c95f773SSathya Perla
13508c95f773SSathya Perla /* For getting a decap_filter_handle we first need to check if
13518c95f773SSathya Perla * there are any other decap flows that share the same tunnel L2
13528c95f773SSathya Perla * key and if so, pass that flow's decap_filter_handle as the
13538c95f773SSathya Perla * ref_decap_handle for this flow.
13548c95f773SSathya Perla */
13558c95f773SSathya Perla rc = bnxt_tc_get_ref_decap_handle(bp, flow, decap_l2_info, flow_node,
13568c95f773SSathya Perla &ref_decap_handle);
13578c95f773SSathya Perla if (rc)
13588c95f773SSathya Perla goto put_decap;
13598c95f773SSathya Perla
13608c95f773SSathya Perla /* Issue the hwrm cmd to allocate a decap filter handle */
13618c95f773SSathya Perla rc = hwrm_cfa_decap_filter_alloc(bp, flow, decap_l2_info,
13628c95f773SSathya Perla ref_decap_handle,
13638c95f773SSathya Perla &decap_node->tunnel_handle);
13648c95f773SSathya Perla if (rc)
13658c95f773SSathya Perla goto put_decap_l2;
13668c95f773SSathya Perla
13678c95f773SSathya Perla done:
13688c95f773SSathya Perla *decap_filter_handle = decap_node->tunnel_handle;
13698c95f773SSathya Perla return 0;
13708c95f773SSathya Perla
13718c95f773SSathya Perla put_decap_l2:
13728c95f773SSathya Perla bnxt_tc_put_decap_l2_node(bp, flow_node);
13738c95f773SSathya Perla put_decap:
13748c95f773SSathya Perla bnxt_tc_put_tunnel_node(bp, &tc_info->decap_table,
13758c95f773SSathya Perla &tc_info->decap_ht_params,
13768c95f773SSathya Perla flow_node->decap_node);
13778c95f773SSathya Perla return rc;
13788c95f773SSathya Perla }
13798c95f773SSathya Perla
bnxt_tc_put_encap_handle(struct bnxt * bp,struct bnxt_tc_tunnel_node * encap_node)13808c95f773SSathya Perla static void bnxt_tc_put_encap_handle(struct bnxt *bp,
13818c95f773SSathya Perla struct bnxt_tc_tunnel_node *encap_node)
13828c95f773SSathya Perla {
13838c95f773SSathya Perla __le32 encap_handle = encap_node->tunnel_handle;
1384cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
13858c95f773SSathya Perla int rc;
13868c95f773SSathya Perla
13878c95f773SSathya Perla rc = bnxt_tc_put_tunnel_node(bp, &tc_info->encap_table,
13888c95f773SSathya Perla &tc_info->encap_ht_params, encap_node);
13898c95f773SSathya Perla if (!rc && encap_handle != INVALID_TUNNEL_HANDLE)
13908c95f773SSathya Perla hwrm_cfa_encap_record_free(bp, encap_handle);
13918c95f773SSathya Perla }
13928c95f773SSathya Perla
13938c95f773SSathya Perla /* Lookup the tunnel encap table and check if there's an encap_handle
13948c95f773SSathya Perla * alloc'd already.
13958c95f773SSathya Perla * If not, query L2 info via a route lookup and issue an encap_record_alloc
13968c95f773SSathya Perla * cmd to FW.
13978c95f773SSathya Perla */
bnxt_tc_get_encap_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_flow_node * flow_node,__le32 * encap_handle)13988c95f773SSathya Perla static int bnxt_tc_get_encap_handle(struct bnxt *bp, struct bnxt_tc_flow *flow,
13998c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node,
14008c95f773SSathya Perla __le32 *encap_handle)
14018c95f773SSathya Perla {
14028c95f773SSathya Perla struct ip_tunnel_key *encap_key = &flow->actions.tun_encap_key;
1403cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
14048c95f773SSathya Perla struct bnxt_tc_tunnel_node *encap_node;
14058c95f773SSathya Perla int rc;
14068c95f773SSathya Perla
14078c95f773SSathya Perla /* Check if there's another flow using the same tunnel encap.
14088c95f773SSathya Perla * If not, add this tunnel to the table and resolve the other
14098c95f773SSathya Perla * tunnel header fileds
14108c95f773SSathya Perla */
14118c95f773SSathya Perla encap_node = bnxt_tc_get_tunnel_node(bp, &tc_info->encap_table,
14128c95f773SSathya Perla &tc_info->encap_ht_params,
14138c95f773SSathya Perla encap_key);
14148c95f773SSathya Perla if (!encap_node)
14158c95f773SSathya Perla return -ENOMEM;
14168c95f773SSathya Perla
14178c95f773SSathya Perla flow_node->encap_node = encap_node;
14188c95f773SSathya Perla
14198c95f773SSathya Perla if (encap_node->tunnel_handle != INVALID_TUNNEL_HANDLE)
14208c95f773SSathya Perla goto done;
14218c95f773SSathya Perla
1422e9ecc731SSathya Perla rc = bnxt_tc_resolve_tunnel_hdrs(bp, encap_key, &encap_node->l2_info);
14238c95f773SSathya Perla if (rc)
14248c95f773SSathya Perla goto put_encap;
14258c95f773SSathya Perla
14268c95f773SSathya Perla /* Allocate a new tunnel encap record */
14278c95f773SSathya Perla rc = hwrm_cfa_encap_record_alloc(bp, encap_key, &encap_node->l2_info,
14288c95f773SSathya Perla &encap_node->tunnel_handle);
14298c95f773SSathya Perla if (rc)
14308c95f773SSathya Perla goto put_encap;
14318c95f773SSathya Perla
14328c95f773SSathya Perla done:
14338c95f773SSathya Perla *encap_handle = encap_node->tunnel_handle;
14348c95f773SSathya Perla return 0;
14358c95f773SSathya Perla
14368c95f773SSathya Perla put_encap:
14378c95f773SSathya Perla bnxt_tc_put_tunnel_node(bp, &tc_info->encap_table,
14388c95f773SSathya Perla &tc_info->encap_ht_params, encap_node);
14398c95f773SSathya Perla return rc;
14408c95f773SSathya Perla }
14418c95f773SSathya Perla
bnxt_tc_put_tunnel_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_flow_node * flow_node)14428c95f773SSathya Perla static void bnxt_tc_put_tunnel_handle(struct bnxt *bp,
14438c95f773SSathya Perla struct bnxt_tc_flow *flow,
14448c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node)
14458c95f773SSathya Perla {
14468c95f773SSathya Perla if (flow->actions.flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP)
14478c95f773SSathya Perla bnxt_tc_put_decap_handle(bp, flow_node);
14488c95f773SSathya Perla else if (flow->actions.flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP)
14498c95f773SSathya Perla bnxt_tc_put_encap_handle(bp, flow_node->encap_node);
14508c95f773SSathya Perla }
14518c95f773SSathya Perla
bnxt_tc_get_tunnel_handle(struct bnxt * bp,struct bnxt_tc_flow * flow,struct bnxt_tc_flow_node * flow_node,__le32 * tunnel_handle)14528c95f773SSathya Perla static int bnxt_tc_get_tunnel_handle(struct bnxt *bp,
14538c95f773SSathya Perla struct bnxt_tc_flow *flow,
14548c95f773SSathya Perla struct bnxt_tc_flow_node *flow_node,
14558c95f773SSathya Perla __le32 *tunnel_handle)
14568c95f773SSathya Perla {
14578c95f773SSathya Perla if (flow->actions.flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP)
14588c95f773SSathya Perla return bnxt_tc_get_decap_handle(bp, flow, flow_node,
14598c95f773SSathya Perla tunnel_handle);
14608c95f773SSathya Perla else if (flow->actions.flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP)
14618c95f773SSathya Perla return bnxt_tc_get_encap_handle(bp, flow, flow_node,
14628c95f773SSathya Perla tunnel_handle);
14638c95f773SSathya Perla else
14648c95f773SSathya Perla return 0;
14658c95f773SSathya Perla }
__bnxt_tc_del_flow(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node)14662ae7408fSSathya Perla static int __bnxt_tc_del_flow(struct bnxt *bp,
14672ae7408fSSathya Perla struct bnxt_tc_flow_node *flow_node)
14682ae7408fSSathya Perla {
1469cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
14702ae7408fSSathya Perla int rc;
14712ae7408fSSathya Perla
14722ae7408fSSathya Perla /* send HWRM cmd to free the flow-id */
1473abd43a13SVenkat Duvvuru bnxt_hwrm_cfa_flow_free(bp, flow_node);
14742ae7408fSSathya Perla
14752ae7408fSSathya Perla mutex_lock(&tc_info->lock);
14762ae7408fSSathya Perla
14778c95f773SSathya Perla /* release references to any tunnel encap/decap nodes */
14788c95f773SSathya Perla bnxt_tc_put_tunnel_handle(bp, &flow_node->flow, flow_node);
14798c95f773SSathya Perla
14802ae7408fSSathya Perla /* release reference to l2 node */
14812ae7408fSSathya Perla bnxt_tc_put_l2_node(bp, flow_node);
14822ae7408fSSathya Perla
14832ae7408fSSathya Perla mutex_unlock(&tc_info->lock);
14842ae7408fSSathya Perla
14852ae7408fSSathya Perla rc = rhashtable_remove_fast(&tc_info->flow_table, &flow_node->node,
14862ae7408fSSathya Perla tc_info->flow_ht_params);
14872ae7408fSSathya Perla if (rc)
14889a005c38SJonathan Lemon netdev_err(bp->dev, "Error: %s: rhashtable_remove_fast rc=%d\n",
14892ae7408fSSathya Perla __func__, rc);
14902ae7408fSSathya Perla
14912ae7408fSSathya Perla kfree_rcu(flow_node, rcu);
14922ae7408fSSathya Perla return 0;
14932ae7408fSSathya Perla }
14942ae7408fSSathya Perla
bnxt_tc_set_flow_dir(struct bnxt * bp,struct bnxt_tc_flow * flow,u16 src_fid)1495abd43a13SVenkat Duvvuru static void bnxt_tc_set_flow_dir(struct bnxt *bp, struct bnxt_tc_flow *flow,
1496abd43a13SVenkat Duvvuru u16 src_fid)
1497abd43a13SVenkat Duvvuru {
14989bf46566SSomnath Kotur flow->l2_key.dir = (bp->pf.fw_fid == src_fid) ? BNXT_DIR_RX : BNXT_DIR_TX;
1499abd43a13SVenkat Duvvuru }
1500abd43a13SVenkat Duvvuru
bnxt_tc_set_src_fid(struct bnxt * bp,struct bnxt_tc_flow * flow,u16 src_fid)1501e9ecc731SSathya Perla static void bnxt_tc_set_src_fid(struct bnxt *bp, struct bnxt_tc_flow *flow,
1502e9ecc731SSathya Perla u16 src_fid)
1503e9ecc731SSathya Perla {
1504e9ecc731SSathya Perla if (flow->actions.flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP)
1505e9ecc731SSathya Perla flow->src_fid = bp->pf.fw_fid;
1506e9ecc731SSathya Perla else
1507e9ecc731SSathya Perla flow->src_fid = src_fid;
1508e9ecc731SSathya Perla }
1509e9ecc731SSathya Perla
15102ae7408fSSathya Perla /* Add a new flow or replace an existing flow.
15112ae7408fSSathya Perla * Notes on locking:
15122ae7408fSSathya Perla * There are essentially two critical sections here.
15132ae7408fSSathya Perla * 1. while adding a new flow
15142ae7408fSSathya Perla * a) lookup l2-key
15152ae7408fSSathya Perla * b) issue HWRM cmd and get flow_handle
15162ae7408fSSathya Perla * c) link l2-key with flow
15172ae7408fSSathya Perla * 2. while deleting a flow
15182ae7408fSSathya Perla * a) unlinking l2-key from flow
15192ae7408fSSathya Perla * A lock is needed to protect these two critical sections.
15202ae7408fSSathya Perla *
15212ae7408fSSathya Perla * The hash-tables are already protected by the rhashtable API.
15222ae7408fSSathya Perla */
bnxt_tc_add_flow(struct bnxt * bp,u16 src_fid,struct flow_cls_offload * tc_flow_cmd)15232ae7408fSSathya Perla static int bnxt_tc_add_flow(struct bnxt *bp, u16 src_fid,
1524f9e30088SPablo Neira Ayuso struct flow_cls_offload *tc_flow_cmd)
15252ae7408fSSathya Perla {
15262ae7408fSSathya Perla struct bnxt_tc_flow_node *new_node, *old_node;
1527cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
15282ae7408fSSathya Perla struct bnxt_tc_flow *flow;
15298c95f773SSathya Perla __le32 tunnel_handle = 0;
15302ae7408fSSathya Perla __le16 ref_flow_handle;
15312ae7408fSSathya Perla int rc;
15322ae7408fSSathya Perla
15332ae7408fSSathya Perla /* allocate memory for the new flow and it's node */
15342ae7408fSSathya Perla new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
15352ae7408fSSathya Perla if (!new_node) {
15362ae7408fSSathya Perla rc = -ENOMEM;
15372ae7408fSSathya Perla goto done;
15382ae7408fSSathya Perla }
15392ae7408fSSathya Perla new_node->cookie = tc_flow_cmd->cookie;
15402ae7408fSSathya Perla flow = &new_node->flow;
15412ae7408fSSathya Perla
15422ae7408fSSathya Perla rc = bnxt_tc_parse_flow(bp, tc_flow_cmd, flow);
15432ae7408fSSathya Perla if (rc)
15442ae7408fSSathya Perla goto free_node;
1545e9ecc731SSathya Perla
1546e9ecc731SSathya Perla bnxt_tc_set_src_fid(bp, flow, src_fid);
1547685ec6a8SVenkat Duvvuru bnxt_tc_set_flow_dir(bp, flow, flow->src_fid);
1548abd43a13SVenkat Duvvuru
15492ae7408fSSathya Perla if (!bnxt_tc_can_offload(bp, flow)) {
1550b2d69122SSriharsha Basavapatna rc = -EOPNOTSUPP;
155108f8280eSSomnath Kotur kfree_rcu(new_node, rcu);
155208f8280eSSomnath Kotur return rc;
15532ae7408fSSathya Perla }
15542ae7408fSSathya Perla
15552ae7408fSSathya Perla /* If a flow exists with the same cookie, delete it */
15562ae7408fSSathya Perla old_node = rhashtable_lookup_fast(&tc_info->flow_table,
15572ae7408fSSathya Perla &tc_flow_cmd->cookie,
15582ae7408fSSathya Perla tc_info->flow_ht_params);
15592ae7408fSSathya Perla if (old_node)
15602ae7408fSSathya Perla __bnxt_tc_del_flow(bp, old_node);
15612ae7408fSSathya Perla
15622ae7408fSSathya Perla /* Check if the L2 part of the flow has been offloaded already.
15632ae7408fSSathya Perla * If so, bump up it's refcnt and get it's reference handle.
15642ae7408fSSathya Perla */
15652ae7408fSSathya Perla mutex_lock(&tc_info->lock);
15662ae7408fSSathya Perla rc = bnxt_tc_get_ref_flow_handle(bp, flow, new_node, &ref_flow_handle);
15672ae7408fSSathya Perla if (rc)
15682ae7408fSSathya Perla goto unlock;
15692ae7408fSSathya Perla
15708c95f773SSathya Perla /* If the flow involves tunnel encap/decap, get tunnel_handle */
15718c95f773SSathya Perla rc = bnxt_tc_get_tunnel_handle(bp, flow, new_node, &tunnel_handle);
15722ae7408fSSathya Perla if (rc)
15732ae7408fSSathya Perla goto put_l2;
15742ae7408fSSathya Perla
15758c95f773SSathya Perla /* send HWRM cmd to alloc the flow */
15768c95f773SSathya Perla rc = bnxt_hwrm_cfa_flow_alloc(bp, flow, ref_flow_handle,
1577abd43a13SVenkat Duvvuru tunnel_handle, new_node);
15788c95f773SSathya Perla if (rc)
15798c95f773SSathya Perla goto put_tunnel;
15808c95f773SSathya Perla
15815a84acbeSSathya Perla flow->lastused = jiffies;
15825a84acbeSSathya Perla spin_lock_init(&flow->stats_lock);
15832ae7408fSSathya Perla /* add new flow to flow-table */
15842ae7408fSSathya Perla rc = rhashtable_insert_fast(&tc_info->flow_table, &new_node->node,
15852ae7408fSSathya Perla tc_info->flow_ht_params);
15862ae7408fSSathya Perla if (rc)
15872ae7408fSSathya Perla goto hwrm_flow_free;
15882ae7408fSSathya Perla
15892ae7408fSSathya Perla mutex_unlock(&tc_info->lock);
15902ae7408fSSathya Perla return 0;
15912ae7408fSSathya Perla
15922ae7408fSSathya Perla hwrm_flow_free:
1593abd43a13SVenkat Duvvuru bnxt_hwrm_cfa_flow_free(bp, new_node);
15948c95f773SSathya Perla put_tunnel:
15958c95f773SSathya Perla bnxt_tc_put_tunnel_handle(bp, flow, new_node);
15962ae7408fSSathya Perla put_l2:
15972ae7408fSSathya Perla bnxt_tc_put_l2_node(bp, new_node);
15982ae7408fSSathya Perla unlock:
15992ae7408fSSathya Perla mutex_unlock(&tc_info->lock);
16002ae7408fSSathya Perla free_node:
16018c95f773SSathya Perla kfree_rcu(new_node, rcu);
16022ae7408fSSathya Perla done:
16039a005c38SJonathan Lemon netdev_err(bp->dev, "Error: %s: cookie=0x%lx error=%d\n",
16042ae7408fSSathya Perla __func__, tc_flow_cmd->cookie, rc);
16052ae7408fSSathya Perla return rc;
16062ae7408fSSathya Perla }
16072ae7408fSSathya Perla
bnxt_tc_del_flow(struct bnxt * bp,struct flow_cls_offload * tc_flow_cmd)16082ae7408fSSathya Perla static int bnxt_tc_del_flow(struct bnxt *bp,
1609f9e30088SPablo Neira Ayuso struct flow_cls_offload *tc_flow_cmd)
16102ae7408fSSathya Perla {
1611cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
16122ae7408fSSathya Perla struct bnxt_tc_flow_node *flow_node;
16132ae7408fSSathya Perla
16142ae7408fSSathya Perla flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
16152ae7408fSSathya Perla &tc_flow_cmd->cookie,
16162ae7408fSSathya Perla tc_info->flow_ht_params);
1617b9ecc340SSriharsha Basavapatna if (!flow_node)
16182ae7408fSSathya Perla return -EINVAL;
16192ae7408fSSathya Perla
16202ae7408fSSathya Perla return __bnxt_tc_del_flow(bp, flow_node);
16212ae7408fSSathya Perla }
16222ae7408fSSathya Perla
bnxt_tc_get_flow_stats(struct bnxt * bp,struct flow_cls_offload * tc_flow_cmd)16232ae7408fSSathya Perla static int bnxt_tc_get_flow_stats(struct bnxt *bp,
1624f9e30088SPablo Neira Ayuso struct flow_cls_offload *tc_flow_cmd)
16252ae7408fSSathya Perla {
16265a84acbeSSathya Perla struct bnxt_tc_flow_stats stats, *curr_stats, *prev_stats;
1627cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
1628d7bc7305SSathya Perla struct bnxt_tc_flow_node *flow_node;
16295a84acbeSSathya Perla struct bnxt_tc_flow *flow;
16305a84acbeSSathya Perla unsigned long lastused;
1631d7bc7305SSathya Perla
1632d7bc7305SSathya Perla flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
1633d7bc7305SSathya Perla &tc_flow_cmd->cookie,
1634d7bc7305SSathya Perla tc_info->flow_ht_params);
1635b9ecc340SSriharsha Basavapatna if (!flow_node)
1636d7bc7305SSathya Perla return -1;
1637d7bc7305SSathya Perla
16385a84acbeSSathya Perla flow = &flow_node->flow;
16395a84acbeSSathya Perla curr_stats = &flow->stats;
16405a84acbeSSathya Perla prev_stats = &flow->prev_stats;
16415a84acbeSSathya Perla
16425a84acbeSSathya Perla spin_lock(&flow->stats_lock);
16435a84acbeSSathya Perla stats.packets = curr_stats->packets - prev_stats->packets;
16445a84acbeSSathya Perla stats.bytes = curr_stats->bytes - prev_stats->bytes;
16455a84acbeSSathya Perla *prev_stats = *curr_stats;
16465a84acbeSSathya Perla lastused = flow->lastused;
16475a84acbeSSathya Perla spin_unlock(&flow->stats_lock);
16485a84acbeSSathya Perla
16494b61d3e8SPo Liu flow_stats_update(&tc_flow_cmd->stats, stats.bytes, stats.packets, 0,
165093a129ebSJiri Pirko lastused, FLOW_ACTION_HW_STATS_DELAYED);
16515a84acbeSSathya Perla return 0;
16525a84acbeSSathya Perla }
16535a84acbeSSathya Perla
bnxt_fill_cfa_stats_req(struct bnxt * bp,struct bnxt_tc_flow_node * flow_node,__le16 * flow_handle,__le32 * flow_id)1654abd43a13SVenkat Duvvuru static void bnxt_fill_cfa_stats_req(struct bnxt *bp,
1655abd43a13SVenkat Duvvuru struct bnxt_tc_flow_node *flow_node,
1656abd43a13SVenkat Duvvuru __le16 *flow_handle, __le32 *flow_id)
1657abd43a13SVenkat Duvvuru {
1658abd43a13SVenkat Duvvuru u16 handle;
1659abd43a13SVenkat Duvvuru
1660abd43a13SVenkat Duvvuru if (bp->fw_cap & BNXT_FW_CAP_OVS_64BIT_HANDLE) {
1661abd43a13SVenkat Duvvuru *flow_id = flow_node->flow_id;
1662abd43a13SVenkat Duvvuru
1663abd43a13SVenkat Duvvuru /* If flow_id is used to fetch flow stats then:
1664abd43a13SVenkat Duvvuru * 1. lower 12 bits of flow_handle must be set to all 1s.
1665abd43a13SVenkat Duvvuru * 2. 15th bit of flow_handle must specify the flow
1666abd43a13SVenkat Duvvuru * direction (TX/RX).
1667abd43a13SVenkat Duvvuru */
16689bf46566SSomnath Kotur if (flow_node->flow.l2_key.dir == BNXT_DIR_RX)
1669abd43a13SVenkat Duvvuru handle = CFA_FLOW_INFO_REQ_FLOW_HANDLE_DIR_RX |
1670abd43a13SVenkat Duvvuru CFA_FLOW_INFO_REQ_FLOW_HANDLE_MAX_MASK;
1671abd43a13SVenkat Duvvuru else
1672abd43a13SVenkat Duvvuru handle = CFA_FLOW_INFO_REQ_FLOW_HANDLE_MAX_MASK;
1673abd43a13SVenkat Duvvuru
1674abd43a13SVenkat Duvvuru *flow_handle = cpu_to_le16(handle);
1675abd43a13SVenkat Duvvuru } else {
1676abd43a13SVenkat Duvvuru *flow_handle = flow_node->flow_handle;
1677abd43a13SVenkat Duvvuru }
1678abd43a13SVenkat Duvvuru }
1679abd43a13SVenkat Duvvuru
16805a84acbeSSathya Perla static int
bnxt_hwrm_cfa_flow_stats_get(struct bnxt * bp,int num_flows,struct bnxt_tc_stats_batch stats_batch[])16815a84acbeSSathya Perla bnxt_hwrm_cfa_flow_stats_get(struct bnxt *bp, int num_flows,
16825a84acbeSSathya Perla struct bnxt_tc_stats_batch stats_batch[])
16835a84acbeSSathya Perla {
16845c209fc8SVenkat Duvvuru struct hwrm_cfa_flow_stats_output *resp;
1685bbf33d1dSEdwin Peer struct hwrm_cfa_flow_stats_input *req;
1686bbf33d1dSEdwin Peer __le16 *req_flow_handles;
1687bbf33d1dSEdwin Peer __le32 *req_flow_ids;
16885a84acbeSSathya Perla int rc, i;
16895a84acbeSSathya Perla
1690bbf33d1dSEdwin Peer rc = hwrm_req_init(bp, req, HWRM_CFA_FLOW_STATS);
1691bbf33d1dSEdwin Peer if (rc)
1692bbf33d1dSEdwin Peer goto exit;
1693bbf33d1dSEdwin Peer
1694bbf33d1dSEdwin Peer req_flow_handles = &req->flow_handle_0;
1695bbf33d1dSEdwin Peer req_flow_ids = &req->flow_id_0;
1696bbf33d1dSEdwin Peer
1697bbf33d1dSEdwin Peer req->num_flows = cpu_to_le16(num_flows);
16985a84acbeSSathya Perla for (i = 0; i < num_flows; i++) {
16995a84acbeSSathya Perla struct bnxt_tc_flow_node *flow_node = stats_batch[i].flow_node;
17005a84acbeSSathya Perla
1701abd43a13SVenkat Duvvuru bnxt_fill_cfa_stats_req(bp, flow_node,
1702abd43a13SVenkat Duvvuru &req_flow_handles[i], &req_flow_ids[i]);
17035a84acbeSSathya Perla }
17045a84acbeSSathya Perla
1705bbf33d1dSEdwin Peer resp = hwrm_req_hold(bp, req);
1706bbf33d1dSEdwin Peer rc = hwrm_req_send(bp, req);
17075a84acbeSSathya Perla if (!rc) {
17085c209fc8SVenkat Duvvuru __le64 *resp_packets;
17095c209fc8SVenkat Duvvuru __le64 *resp_bytes;
17105c209fc8SVenkat Duvvuru
17115c209fc8SVenkat Duvvuru resp_packets = &resp->packet_0;
17125c209fc8SVenkat Duvvuru resp_bytes = &resp->byte_0;
17135a84acbeSSathya Perla
17145a84acbeSSathya Perla for (i = 0; i < num_flows; i++) {
17155a84acbeSSathya Perla stats_batch[i].hw_stats.packets =
17165a84acbeSSathya Perla le64_to_cpu(resp_packets[i]);
17175a84acbeSSathya Perla stats_batch[i].hw_stats.bytes =
17185a84acbeSSathya Perla le64_to_cpu(resp_bytes[i]);
17195a84acbeSSathya Perla }
17205a84acbeSSathya Perla }
1721bbf33d1dSEdwin Peer hwrm_req_drop(bp, req);
1722bbf33d1dSEdwin Peer exit:
1723bbf33d1dSEdwin Peer if (rc)
1724bbf33d1dSEdwin Peer netdev_info(bp->dev, "error rc=%d\n", rc);
17256ae777eaSVenkat Duvvuru
17265a84acbeSSathya Perla return rc;
17275a84acbeSSathya Perla }
17285a84acbeSSathya Perla
17295a84acbeSSathya Perla /* Add val to accum while handling a possible wraparound
17305a84acbeSSathya Perla * of val. Eventhough val is of type u64, its actual width
17315a84acbeSSathya Perla * is denoted by mask and will wrap-around beyond that width.
17325a84acbeSSathya Perla */
accumulate_val(u64 * accum,u64 val,u64 mask)17335a84acbeSSathya Perla static void accumulate_val(u64 *accum, u64 val, u64 mask)
17345a84acbeSSathya Perla {
17355a84acbeSSathya Perla #define low_bits(x, mask) ((x) & (mask))
17365a84acbeSSathya Perla #define high_bits(x, mask) ((x) & ~(mask))
17375a84acbeSSathya Perla bool wrapped = val < low_bits(*accum, mask);
17385a84acbeSSathya Perla
17395a84acbeSSathya Perla *accum = high_bits(*accum, mask) + val;
17405a84acbeSSathya Perla if (wrapped)
17415a84acbeSSathya Perla *accum += (mask + 1);
17425a84acbeSSathya Perla }
17435a84acbeSSathya Perla
17445a84acbeSSathya Perla /* The HW counters' width is much less than 64bits.
17455a84acbeSSathya Perla * Handle possible wrap-around while updating the stat counters
17465a84acbeSSathya Perla */
bnxt_flow_stats_accum(struct bnxt_tc_info * tc_info,struct bnxt_tc_flow_stats * acc_stats,struct bnxt_tc_flow_stats * hw_stats)17475a84acbeSSathya Perla static void bnxt_flow_stats_accum(struct bnxt_tc_info *tc_info,
17485a84acbeSSathya Perla struct bnxt_tc_flow_stats *acc_stats,
17495a84acbeSSathya Perla struct bnxt_tc_flow_stats *hw_stats)
17505a84acbeSSathya Perla {
17515a84acbeSSathya Perla accumulate_val(&acc_stats->bytes, hw_stats->bytes, tc_info->bytes_mask);
17525a84acbeSSathya Perla accumulate_val(&acc_stats->packets, hw_stats->packets,
17535a84acbeSSathya Perla tc_info->packets_mask);
17545a84acbeSSathya Perla }
17555a84acbeSSathya Perla
17565a84acbeSSathya Perla static int
bnxt_tc_flow_stats_batch_update(struct bnxt * bp,int num_flows,struct bnxt_tc_stats_batch stats_batch[])17575a84acbeSSathya Perla bnxt_tc_flow_stats_batch_update(struct bnxt *bp, int num_flows,
17585a84acbeSSathya Perla struct bnxt_tc_stats_batch stats_batch[])
17595a84acbeSSathya Perla {
1760cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
17615a84acbeSSathya Perla int rc, i;
17625a84acbeSSathya Perla
17635a84acbeSSathya Perla rc = bnxt_hwrm_cfa_flow_stats_get(bp, num_flows, stats_batch);
1764d7bc7305SSathya Perla if (rc)
1765d7bc7305SSathya Perla return rc;
1766d7bc7305SSathya Perla
17675a84acbeSSathya Perla for (i = 0; i < num_flows; i++) {
17685a84acbeSSathya Perla struct bnxt_tc_flow_node *flow_node = stats_batch[i].flow_node;
17695a84acbeSSathya Perla struct bnxt_tc_flow *flow = &flow_node->flow;
17705a84acbeSSathya Perla
17715a84acbeSSathya Perla spin_lock(&flow->stats_lock);
17725a84acbeSSathya Perla bnxt_flow_stats_accum(tc_info, &flow->stats,
17735a84acbeSSathya Perla &stats_batch[i].hw_stats);
17745a84acbeSSathya Perla if (flow->stats.packets != flow->prev_stats.packets)
17755a84acbeSSathya Perla flow->lastused = jiffies;
17765a84acbeSSathya Perla spin_unlock(&flow->stats_lock);
17775a84acbeSSathya Perla }
17785a84acbeSSathya Perla
17792ae7408fSSathya Perla return 0;
17802ae7408fSSathya Perla }
17812ae7408fSSathya Perla
17825a84acbeSSathya Perla static int
bnxt_tc_flow_stats_batch_prep(struct bnxt * bp,struct bnxt_tc_stats_batch stats_batch[],int * num_flows)17835a84acbeSSathya Perla bnxt_tc_flow_stats_batch_prep(struct bnxt *bp,
17845a84acbeSSathya Perla struct bnxt_tc_stats_batch stats_batch[],
17855a84acbeSSathya Perla int *num_flows)
17865a84acbeSSathya Perla {
1787cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
17885a84acbeSSathya Perla struct rhashtable_iter *iter = &tc_info->iter;
17895a84acbeSSathya Perla void *flow_node;
17905a84acbeSSathya Perla int rc, i;
17915a84acbeSSathya Perla
179297a6ec4aSTom Herbert rhashtable_walk_start(iter);
17935a84acbeSSathya Perla
17945a84acbeSSathya Perla rc = 0;
17955a84acbeSSathya Perla for (i = 0; i < BNXT_FLOW_STATS_BATCH_MAX; i++) {
17965a84acbeSSathya Perla flow_node = rhashtable_walk_next(iter);
17975a84acbeSSathya Perla if (IS_ERR(flow_node)) {
17985a84acbeSSathya Perla i = 0;
17995a84acbeSSathya Perla if (PTR_ERR(flow_node) == -EAGAIN) {
18005a84acbeSSathya Perla continue;
18015a84acbeSSathya Perla } else {
18025a84acbeSSathya Perla rc = PTR_ERR(flow_node);
18035a84acbeSSathya Perla goto done;
18045a84acbeSSathya Perla }
18055a84acbeSSathya Perla }
18065a84acbeSSathya Perla
18075a84acbeSSathya Perla /* No more flows */
18085a84acbeSSathya Perla if (!flow_node)
18095a84acbeSSathya Perla goto done;
18105a84acbeSSathya Perla
18115a84acbeSSathya Perla stats_batch[i].flow_node = flow_node;
18125a84acbeSSathya Perla }
18135a84acbeSSathya Perla done:
18145a84acbeSSathya Perla rhashtable_walk_stop(iter);
18155a84acbeSSathya Perla *num_flows = i;
18165a84acbeSSathya Perla return rc;
18175a84acbeSSathya Perla }
18185a84acbeSSathya Perla
bnxt_tc_flow_stats_work(struct bnxt * bp)18195a84acbeSSathya Perla void bnxt_tc_flow_stats_work(struct bnxt *bp)
18205a84acbeSSathya Perla {
1821cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
18225a84acbeSSathya Perla int num_flows, rc;
18235a84acbeSSathya Perla
18245a84acbeSSathya Perla num_flows = atomic_read(&tc_info->flow_table.nelems);
18255a84acbeSSathya Perla if (!num_flows)
18265a84acbeSSathya Perla return;
18275a84acbeSSathya Perla
18285a84acbeSSathya Perla rhashtable_walk_enter(&tc_info->flow_table, &tc_info->iter);
18295a84acbeSSathya Perla
18305a84acbeSSathya Perla for (;;) {
18315a84acbeSSathya Perla rc = bnxt_tc_flow_stats_batch_prep(bp, tc_info->stats_batch,
18325a84acbeSSathya Perla &num_flows);
18335a84acbeSSathya Perla if (rc) {
18345a84acbeSSathya Perla if (rc == -EAGAIN)
18355a84acbeSSathya Perla continue;
18365a84acbeSSathya Perla break;
18375a84acbeSSathya Perla }
18385a84acbeSSathya Perla
18395a84acbeSSathya Perla if (!num_flows)
18405a84acbeSSathya Perla break;
18415a84acbeSSathya Perla
18425a84acbeSSathya Perla bnxt_tc_flow_stats_batch_update(bp, num_flows,
18435a84acbeSSathya Perla tc_info->stats_batch);
18445a84acbeSSathya Perla }
18455a84acbeSSathya Perla
18465a84acbeSSathya Perla rhashtable_walk_exit(&tc_info->iter);
18475a84acbeSSathya Perla }
18485a84acbeSSathya Perla
bnxt_tc_setup_flower(struct bnxt * bp,u16 src_fid,struct flow_cls_offload * cls_flower)18492ae7408fSSathya Perla int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
1850f9e30088SPablo Neira Ayuso struct flow_cls_offload *cls_flower)
18512ae7408fSSathya Perla {
18522ae7408fSSathya Perla switch (cls_flower->command) {
1853f9e30088SPablo Neira Ayuso case FLOW_CLS_REPLACE:
185483741bb0SJiri Pirko return bnxt_tc_add_flow(bp, src_fid, cls_flower);
1855f9e30088SPablo Neira Ayuso case FLOW_CLS_DESTROY:
185683741bb0SJiri Pirko return bnxt_tc_del_flow(bp, cls_flower);
1857f9e30088SPablo Neira Ayuso case FLOW_CLS_STATS:
185883741bb0SJiri Pirko return bnxt_tc_get_flow_stats(bp, cls_flower);
185983741bb0SJiri Pirko default:
186083741bb0SJiri Pirko return -EOPNOTSUPP;
18612ae7408fSSathya Perla }
18622ae7408fSSathya Perla }
18632ae7408fSSathya Perla
bnxt_tc_setup_indr_block_cb(enum tc_setup_type type,void * type_data,void * cb_priv)1864627c89d0SSriharsha Basavapatna static int bnxt_tc_setup_indr_block_cb(enum tc_setup_type type,
1865627c89d0SSriharsha Basavapatna void *type_data, void *cb_priv)
1866627c89d0SSriharsha Basavapatna {
1867627c89d0SSriharsha Basavapatna struct bnxt_flower_indr_block_cb_priv *priv = cb_priv;
1868627c89d0SSriharsha Basavapatna struct flow_cls_offload *flower = type_data;
1869627c89d0SSriharsha Basavapatna struct bnxt *bp = priv->bp;
1870627c89d0SSriharsha Basavapatna
1871b0757491SSriharsha Basavapatna if (!tc_cls_can_offload_and_chain0(bp->dev, type_data))
1872627c89d0SSriharsha Basavapatna return -EOPNOTSUPP;
1873627c89d0SSriharsha Basavapatna
1874627c89d0SSriharsha Basavapatna switch (type) {
1875627c89d0SSriharsha Basavapatna case TC_SETUP_CLSFLOWER:
1876627c89d0SSriharsha Basavapatna return bnxt_tc_setup_flower(bp, bp->pf.fw_fid, flower);
1877627c89d0SSriharsha Basavapatna default:
1878627c89d0SSriharsha Basavapatna return -EOPNOTSUPP;
1879627c89d0SSriharsha Basavapatna }
1880627c89d0SSriharsha Basavapatna }
1881627c89d0SSriharsha Basavapatna
1882627c89d0SSriharsha Basavapatna static struct bnxt_flower_indr_block_cb_priv *
bnxt_tc_indr_block_cb_lookup(struct bnxt * bp,struct net_device * netdev)1883627c89d0SSriharsha Basavapatna bnxt_tc_indr_block_cb_lookup(struct bnxt *bp, struct net_device *netdev)
1884627c89d0SSriharsha Basavapatna {
1885627c89d0SSriharsha Basavapatna struct bnxt_flower_indr_block_cb_priv *cb_priv;
1886627c89d0SSriharsha Basavapatna
1887627c89d0SSriharsha Basavapatna list_for_each_entry(cb_priv, &bp->tc_indr_block_list, list)
1888627c89d0SSriharsha Basavapatna if (cb_priv->tunnel_netdev == netdev)
1889627c89d0SSriharsha Basavapatna return cb_priv;
1890627c89d0SSriharsha Basavapatna
1891627c89d0SSriharsha Basavapatna return NULL;
1892627c89d0SSriharsha Basavapatna }
1893627c89d0SSriharsha Basavapatna
bnxt_tc_setup_indr_rel(void * cb_priv)1894627c89d0SSriharsha Basavapatna static void bnxt_tc_setup_indr_rel(void *cb_priv)
1895627c89d0SSriharsha Basavapatna {
1896627c89d0SSriharsha Basavapatna struct bnxt_flower_indr_block_cb_priv *priv = cb_priv;
1897627c89d0SSriharsha Basavapatna
1898627c89d0SSriharsha Basavapatna list_del(&priv->list);
1899627c89d0SSriharsha Basavapatna kfree(priv);
1900627c89d0SSriharsha Basavapatna }
1901627c89d0SSriharsha Basavapatna
bnxt_tc_setup_indr_block(struct net_device * netdev,struct Qdisc * sch,struct bnxt * bp,struct flow_block_offload * f,void * data,void (* cleanup)(struct flow_block_cb * block_cb))1902c40f4e50SPetr Machata static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct Qdisc *sch, struct bnxt *bp,
190366f1939aSwenxu struct flow_block_offload *f, void *data,
190466f1939aSwenxu void (*cleanup)(struct flow_block_cb *block_cb))
1905627c89d0SSriharsha Basavapatna {
1906627c89d0SSriharsha Basavapatna struct bnxt_flower_indr_block_cb_priv *cb_priv;
1907627c89d0SSriharsha Basavapatna struct flow_block_cb *block_cb;
1908627c89d0SSriharsha Basavapatna
1909627c89d0SSriharsha Basavapatna if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
1910627c89d0SSriharsha Basavapatna return -EOPNOTSUPP;
1911627c89d0SSriharsha Basavapatna
1912627c89d0SSriharsha Basavapatna switch (f->command) {
1913627c89d0SSriharsha Basavapatna case FLOW_BLOCK_BIND:
1914627c89d0SSriharsha Basavapatna cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
1915627c89d0SSriharsha Basavapatna if (!cb_priv)
1916627c89d0SSriharsha Basavapatna return -ENOMEM;
1917627c89d0SSriharsha Basavapatna
1918627c89d0SSriharsha Basavapatna cb_priv->tunnel_netdev = netdev;
1919627c89d0SSriharsha Basavapatna cb_priv->bp = bp;
1920627c89d0SSriharsha Basavapatna list_add(&cb_priv->list, &bp->tc_indr_block_list);
1921627c89d0SSriharsha Basavapatna
192266f1939aSwenxu block_cb = flow_indr_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
1923627c89d0SSriharsha Basavapatna cb_priv, cb_priv,
192466f1939aSwenxu bnxt_tc_setup_indr_rel, f,
1925c40f4e50SPetr Machata netdev, sch, data, bp, cleanup);
1926627c89d0SSriharsha Basavapatna if (IS_ERR(block_cb)) {
1927627c89d0SSriharsha Basavapatna list_del(&cb_priv->list);
1928627c89d0SSriharsha Basavapatna kfree(cb_priv);
1929627c89d0SSriharsha Basavapatna return PTR_ERR(block_cb);
1930627c89d0SSriharsha Basavapatna }
1931627c89d0SSriharsha Basavapatna
1932627c89d0SSriharsha Basavapatna flow_block_cb_add(block_cb, f);
1933627c89d0SSriharsha Basavapatna list_add_tail(&block_cb->driver_list, &bnxt_block_cb_list);
1934627c89d0SSriharsha Basavapatna break;
1935627c89d0SSriharsha Basavapatna case FLOW_BLOCK_UNBIND:
1936627c89d0SSriharsha Basavapatna cb_priv = bnxt_tc_indr_block_cb_lookup(bp, netdev);
1937627c89d0SSriharsha Basavapatna if (!cb_priv)
1938627c89d0SSriharsha Basavapatna return -ENOENT;
1939627c89d0SSriharsha Basavapatna
1940627c89d0SSriharsha Basavapatna block_cb = flow_block_cb_lookup(f->block,
1941627c89d0SSriharsha Basavapatna bnxt_tc_setup_indr_block_cb,
1942627c89d0SSriharsha Basavapatna cb_priv);
1943627c89d0SSriharsha Basavapatna if (!block_cb)
1944627c89d0SSriharsha Basavapatna return -ENOENT;
1945627c89d0SSriharsha Basavapatna
194666f1939aSwenxu flow_indr_block_cb_remove(block_cb, f);
1947627c89d0SSriharsha Basavapatna list_del(&block_cb->driver_list);
1948627c89d0SSriharsha Basavapatna break;
1949627c89d0SSriharsha Basavapatna default:
1950627c89d0SSriharsha Basavapatna return -EOPNOTSUPP;
1951627c89d0SSriharsha Basavapatna }
1952627c89d0SSriharsha Basavapatna return 0;
1953627c89d0SSriharsha Basavapatna }
1954627c89d0SSriharsha Basavapatna
bnxt_is_netdev_indr_offload(struct net_device * netdev)1955627c89d0SSriharsha Basavapatna static bool bnxt_is_netdev_indr_offload(struct net_device *netdev)
1956627c89d0SSriharsha Basavapatna {
1957627c89d0SSriharsha Basavapatna return netif_is_vxlan(netdev);
1958627c89d0SSriharsha Basavapatna }
1959627c89d0SSriharsha Basavapatna
bnxt_tc_setup_indr_cb(struct net_device * netdev,struct Qdisc * sch,void * cb_priv,enum tc_setup_type type,void * type_data,void * data,void (* cleanup)(struct flow_block_cb * block_cb))1960c40f4e50SPetr Machata static int bnxt_tc_setup_indr_cb(struct net_device *netdev, struct Qdisc *sch, void *cb_priv,
196166f1939aSwenxu enum tc_setup_type type, void *type_data,
196266f1939aSwenxu void *data,
196366f1939aSwenxu void (*cleanup)(struct flow_block_cb *block_cb))
1964627c89d0SSriharsha Basavapatna {
1965144d4c9eSBaowen Zheng if (!netdev || !bnxt_is_netdev_indr_offload(netdev))
1966e445e30cSPablo Neira Ayuso return -EOPNOTSUPP;
1967627c89d0SSriharsha Basavapatna
1968e445e30cSPablo Neira Ayuso switch (type) {
1969e445e30cSPablo Neira Ayuso case TC_SETUP_BLOCK:
1970c40f4e50SPetr Machata return bnxt_tc_setup_indr_block(netdev, sch, cb_priv, type_data, data, cleanup);
1971e445e30cSPablo Neira Ayuso default:
1972627c89d0SSriharsha Basavapatna break;
1973627c89d0SSriharsha Basavapatna }
1974627c89d0SSriharsha Basavapatna
1975e445e30cSPablo Neira Ayuso return -EOPNOTSUPP;
1976627c89d0SSriharsha Basavapatna }
1977627c89d0SSriharsha Basavapatna
19782ae7408fSSathya Perla static const struct rhashtable_params bnxt_tc_flow_ht_params = {
19792ae7408fSSathya Perla .head_offset = offsetof(struct bnxt_tc_flow_node, node),
19802ae7408fSSathya Perla .key_offset = offsetof(struct bnxt_tc_flow_node, cookie),
19812ae7408fSSathya Perla .key_len = sizeof(((struct bnxt_tc_flow_node *)0)->cookie),
19822ae7408fSSathya Perla .automatic_shrinking = true
19832ae7408fSSathya Perla };
19842ae7408fSSathya Perla
19852ae7408fSSathya Perla static const struct rhashtable_params bnxt_tc_l2_ht_params = {
19862ae7408fSSathya Perla .head_offset = offsetof(struct bnxt_tc_l2_node, node),
19872ae7408fSSathya Perla .key_offset = offsetof(struct bnxt_tc_l2_node, key),
19882ae7408fSSathya Perla .key_len = BNXT_TC_L2_KEY_LEN,
19892ae7408fSSathya Perla .automatic_shrinking = true
19902ae7408fSSathya Perla };
19912ae7408fSSathya Perla
19928c95f773SSathya Perla static const struct rhashtable_params bnxt_tc_decap_l2_ht_params = {
19938c95f773SSathya Perla .head_offset = offsetof(struct bnxt_tc_l2_node, node),
19948c95f773SSathya Perla .key_offset = offsetof(struct bnxt_tc_l2_node, key),
19958c95f773SSathya Perla .key_len = BNXT_TC_L2_KEY_LEN,
19968c95f773SSathya Perla .automatic_shrinking = true
19978c95f773SSathya Perla };
19988c95f773SSathya Perla
19998c95f773SSathya Perla static const struct rhashtable_params bnxt_tc_tunnel_ht_params = {
20008c95f773SSathya Perla .head_offset = offsetof(struct bnxt_tc_tunnel_node, node),
20018c95f773SSathya Perla .key_offset = offsetof(struct bnxt_tc_tunnel_node, key),
20028c95f773SSathya Perla .key_len = sizeof(struct ip_tunnel_key),
20038c95f773SSathya Perla .automatic_shrinking = true
20048c95f773SSathya Perla };
20058c95f773SSathya Perla
20062ae7408fSSathya Perla /* convert counter width in bits to a mask */
20072ae7408fSSathya Perla #define mask(width) ((u64)~0 >> (64 - (width)))
20082ae7408fSSathya Perla
bnxt_init_tc(struct bnxt * bp)20092ae7408fSSathya Perla int bnxt_init_tc(struct bnxt *bp)
20102ae7408fSSathya Perla {
2011cd66358eSSathya Perla struct bnxt_tc_info *tc_info;
20122ae7408fSSathya Perla int rc;
20132ae7408fSSathya Perla
201418c7015cSJakub Kicinski if (bp->hwrm_spec_code < 0x10803)
201518c7015cSJakub Kicinski return 0;
2016cd66358eSSathya Perla
2017cd66358eSSathya Perla tc_info = kzalloc(sizeof(*tc_info), GFP_KERNEL);
2018cd66358eSSathya Perla if (!tc_info)
2019cd66358eSSathya Perla return -ENOMEM;
20202ae7408fSSathya Perla mutex_init(&tc_info->lock);
20212ae7408fSSathya Perla
20222ae7408fSSathya Perla /* Counter widths are programmed by FW */
20232ae7408fSSathya Perla tc_info->bytes_mask = mask(36);
20242ae7408fSSathya Perla tc_info->packets_mask = mask(28);
20252ae7408fSSathya Perla
20262ae7408fSSathya Perla tc_info->flow_ht_params = bnxt_tc_flow_ht_params;
20272ae7408fSSathya Perla rc = rhashtable_init(&tc_info->flow_table, &tc_info->flow_ht_params);
20282ae7408fSSathya Perla if (rc)
2029cd66358eSSathya Perla goto free_tc_info;
20302ae7408fSSathya Perla
20312ae7408fSSathya Perla tc_info->l2_ht_params = bnxt_tc_l2_ht_params;
20322ae7408fSSathya Perla rc = rhashtable_init(&tc_info->l2_table, &tc_info->l2_ht_params);
20332ae7408fSSathya Perla if (rc)
20342ae7408fSSathya Perla goto destroy_flow_table;
20352ae7408fSSathya Perla
20368c95f773SSathya Perla tc_info->decap_l2_ht_params = bnxt_tc_decap_l2_ht_params;
20378c95f773SSathya Perla rc = rhashtable_init(&tc_info->decap_l2_table,
20388c95f773SSathya Perla &tc_info->decap_l2_ht_params);
20398c95f773SSathya Perla if (rc)
20408c95f773SSathya Perla goto destroy_l2_table;
20418c95f773SSathya Perla
20428c95f773SSathya Perla tc_info->decap_ht_params = bnxt_tc_tunnel_ht_params;
20438c95f773SSathya Perla rc = rhashtable_init(&tc_info->decap_table,
20448c95f773SSathya Perla &tc_info->decap_ht_params);
20458c95f773SSathya Perla if (rc)
20468c95f773SSathya Perla goto destroy_decap_l2_table;
20478c95f773SSathya Perla
20488c95f773SSathya Perla tc_info->encap_ht_params = bnxt_tc_tunnel_ht_params;
20498c95f773SSathya Perla rc = rhashtable_init(&tc_info->encap_table,
20508c95f773SSathya Perla &tc_info->encap_ht_params);
20518c95f773SSathya Perla if (rc)
20528c95f773SSathya Perla goto destroy_decap_table;
20538c95f773SSathya Perla
20542ae7408fSSathya Perla tc_info->enabled = true;
20552ae7408fSSathya Perla bp->dev->hw_features |= NETIF_F_HW_TC;
20562ae7408fSSathya Perla bp->dev->features |= NETIF_F_HW_TC;
2057cd66358eSSathya Perla bp->tc_info = tc_info;
2058627c89d0SSriharsha Basavapatna
2059627c89d0SSriharsha Basavapatna /* init indirect block notifications */
2060627c89d0SSriharsha Basavapatna INIT_LIST_HEAD(&bp->tc_indr_block_list);
2061e445e30cSPablo Neira Ayuso
2062e445e30cSPablo Neira Ayuso rc = flow_indr_dev_register(bnxt_tc_setup_indr_cb, bp);
2063627c89d0SSriharsha Basavapatna if (!rc)
20642ae7408fSSathya Perla return 0;
20652ae7408fSSathya Perla
2066627c89d0SSriharsha Basavapatna rhashtable_destroy(&tc_info->encap_table);
2067627c89d0SSriharsha Basavapatna
20688c95f773SSathya Perla destroy_decap_table:
20698c95f773SSathya Perla rhashtable_destroy(&tc_info->decap_table);
20708c95f773SSathya Perla destroy_decap_l2_table:
20718c95f773SSathya Perla rhashtable_destroy(&tc_info->decap_l2_table);
20728c95f773SSathya Perla destroy_l2_table:
20738c95f773SSathya Perla rhashtable_destroy(&tc_info->l2_table);
20742ae7408fSSathya Perla destroy_flow_table:
20752ae7408fSSathya Perla rhashtable_destroy(&tc_info->flow_table);
2076cd66358eSSathya Perla free_tc_info:
2077cd66358eSSathya Perla kfree(tc_info);
2078*dc903ddcSDinghao Liu bp->tc_info = NULL;
20792ae7408fSSathya Perla return rc;
20802ae7408fSSathya Perla }
20812ae7408fSSathya Perla
bnxt_shutdown_tc(struct bnxt * bp)20822ae7408fSSathya Perla void bnxt_shutdown_tc(struct bnxt *bp)
20832ae7408fSSathya Perla {
2084cd66358eSSathya Perla struct bnxt_tc_info *tc_info = bp->tc_info;
20852ae7408fSSathya Perla
2086cd66358eSSathya Perla if (!bnxt_tc_flower_enabled(bp))
20872ae7408fSSathya Perla return;
20882ae7408fSSathya Perla
2089e445e30cSPablo Neira Ayuso flow_indr_dev_unregister(bnxt_tc_setup_indr_cb, bp,
2090a1db2178Swenxu bnxt_tc_setup_indr_rel);
20912ae7408fSSathya Perla rhashtable_destroy(&tc_info->flow_table);
20922ae7408fSSathya Perla rhashtable_destroy(&tc_info->l2_table);
20938c95f773SSathya Perla rhashtable_destroy(&tc_info->decap_l2_table);
20948c95f773SSathya Perla rhashtable_destroy(&tc_info->decap_table);
20958c95f773SSathya Perla rhashtable_destroy(&tc_info->encap_table);
2096cd66358eSSathya Perla kfree(tc_info);
2097cd66358eSSathya Perla bp->tc_info = NULL;
20982ae7408fSSathya Perla }
2099