1c10d12e3SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2c10d12e3SJakub Kicinski /* Copyright (C) 2015-2019 Netronome Systems, Inc. */
3c10d12e3SJakub Kicinski
4c10d12e3SJakub Kicinski #include <linux/bpf_trace.h>
5c10d12e3SJakub Kicinski #include <linux/netdevice.h>
6c10d12e3SJakub Kicinski #include <linux/overflow.h>
7c10d12e3SJakub Kicinski #include <linux/sizes.h>
8c10d12e3SJakub Kicinski #include <linux/bitfield.h>
9436396f2SHuanhuan Wang #include <net/xfrm.h>
10c10d12e3SJakub Kicinski
11c10d12e3SJakub Kicinski #include "../nfp_app.h"
12c10d12e3SJakub Kicinski #include "../nfp_net.h"
13c10d12e3SJakub Kicinski #include "../nfp_net_dp.h"
14c10d12e3SJakub Kicinski #include "../crypto/crypto.h"
15c10d12e3SJakub Kicinski #include "../crypto/fw.h"
16c10d12e3SJakub Kicinski #include "nfdk.h"
17c10d12e3SJakub Kicinski
nfp_nfdk_tx_ring_should_wake(struct nfp_net_tx_ring * tx_ring)18c10d12e3SJakub Kicinski static int nfp_nfdk_tx_ring_should_wake(struct nfp_net_tx_ring *tx_ring)
19c10d12e3SJakub Kicinski {
20c10d12e3SJakub Kicinski return !nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT * 2);
21c10d12e3SJakub Kicinski }
22c10d12e3SJakub Kicinski
nfp_nfdk_tx_ring_should_stop(struct nfp_net_tx_ring * tx_ring)23c10d12e3SJakub Kicinski static int nfp_nfdk_tx_ring_should_stop(struct nfp_net_tx_ring *tx_ring)
24c10d12e3SJakub Kicinski {
25c10d12e3SJakub Kicinski return nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT);
26c10d12e3SJakub Kicinski }
27c10d12e3SJakub Kicinski
nfp_nfdk_tx_ring_stop(struct netdev_queue * nd_q,struct nfp_net_tx_ring * tx_ring)28c10d12e3SJakub Kicinski static void nfp_nfdk_tx_ring_stop(struct netdev_queue *nd_q,
29c10d12e3SJakub Kicinski struct nfp_net_tx_ring *tx_ring)
30c10d12e3SJakub Kicinski {
31c10d12e3SJakub Kicinski netif_tx_stop_queue(nd_q);
32c10d12e3SJakub Kicinski
33c10d12e3SJakub Kicinski /* We can race with the TX completion out of NAPI so recheck */
34c10d12e3SJakub Kicinski smp_mb();
35c10d12e3SJakub Kicinski if (unlikely(nfp_nfdk_tx_ring_should_wake(tx_ring)))
36c10d12e3SJakub Kicinski netif_tx_start_queue(nd_q);
37c10d12e3SJakub Kicinski }
38c10d12e3SJakub Kicinski
39c10d12e3SJakub Kicinski static __le64
nfp_nfdk_tx_tso(struct nfp_net_r_vector * r_vec,struct nfp_nfdk_tx_buf * txbuf,struct sk_buff * skb)40c10d12e3SJakub Kicinski nfp_nfdk_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfdk_tx_buf *txbuf,
41c10d12e3SJakub Kicinski struct sk_buff *skb)
42c10d12e3SJakub Kicinski {
43c10d12e3SJakub Kicinski u32 segs, hdrlen, l3_offset, l4_offset;
44c10d12e3SJakub Kicinski struct nfp_nfdk_tx_desc txd;
45c10d12e3SJakub Kicinski u16 mss;
46c10d12e3SJakub Kicinski
47c10d12e3SJakub Kicinski if (!skb->encapsulation) {
48c10d12e3SJakub Kicinski l3_offset = skb_network_offset(skb);
49c10d12e3SJakub Kicinski l4_offset = skb_transport_offset(skb);
50504148feSEric Dumazet hdrlen = skb_tcp_all_headers(skb);
51c10d12e3SJakub Kicinski } else {
52c10d12e3SJakub Kicinski l3_offset = skb_inner_network_offset(skb);
53c10d12e3SJakub Kicinski l4_offset = skb_inner_transport_offset(skb);
54504148feSEric Dumazet hdrlen = skb_inner_tcp_all_headers(skb);
55c10d12e3SJakub Kicinski }
56c10d12e3SJakub Kicinski
57c10d12e3SJakub Kicinski segs = skb_shinfo(skb)->gso_segs;
58c10d12e3SJakub Kicinski mss = skb_shinfo(skb)->gso_size & NFDK_DESC_TX_MSS_MASK;
59c10d12e3SJakub Kicinski
60c10d12e3SJakub Kicinski txd.l3_offset = l3_offset;
61c10d12e3SJakub Kicinski txd.l4_offset = l4_offset;
62c10d12e3SJakub Kicinski txd.lso_meta_res = 0;
63c10d12e3SJakub Kicinski txd.mss = cpu_to_le16(mss);
64c10d12e3SJakub Kicinski txd.lso_hdrlen = hdrlen;
65c10d12e3SJakub Kicinski txd.lso_totsegs = segs;
66c10d12e3SJakub Kicinski
67c10d12e3SJakub Kicinski txbuf->pkt_cnt = segs;
68c10d12e3SJakub Kicinski txbuf->real_len = skb->len + hdrlen * (txbuf->pkt_cnt - 1);
69c10d12e3SJakub Kicinski
70c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
71c10d12e3SJakub Kicinski r_vec->tx_lso++;
72c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
73c10d12e3SJakub Kicinski
74c10d12e3SJakub Kicinski return txd.raw;
75c10d12e3SJakub Kicinski }
76c10d12e3SJakub Kicinski
77c10d12e3SJakub Kicinski static u8
nfp_nfdk_tx_csum(struct nfp_net_dp * dp,struct nfp_net_r_vector * r_vec,unsigned int pkt_cnt,struct sk_buff * skb,u64 flags)78c10d12e3SJakub Kicinski nfp_nfdk_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
79c10d12e3SJakub Kicinski unsigned int pkt_cnt, struct sk_buff *skb, u64 flags)
80c10d12e3SJakub Kicinski {
81c10d12e3SJakub Kicinski struct ipv6hdr *ipv6h;
82c10d12e3SJakub Kicinski struct iphdr *iph;
83c10d12e3SJakub Kicinski
84c10d12e3SJakub Kicinski if (!(dp->ctrl & NFP_NET_CFG_CTRL_TXCSUM))
85c10d12e3SJakub Kicinski return flags;
86c10d12e3SJakub Kicinski
87c10d12e3SJakub Kicinski if (skb->ip_summed != CHECKSUM_PARTIAL)
88c10d12e3SJakub Kicinski return flags;
89c10d12e3SJakub Kicinski
90c10d12e3SJakub Kicinski flags |= NFDK_DESC_TX_L4_CSUM;
91c10d12e3SJakub Kicinski
92c10d12e3SJakub Kicinski iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
93c10d12e3SJakub Kicinski ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
94c10d12e3SJakub Kicinski
95c10d12e3SJakub Kicinski /* L3 checksum offloading flag is not required for ipv6 */
96c10d12e3SJakub Kicinski if (iph->version == 4) {
97c10d12e3SJakub Kicinski flags |= NFDK_DESC_TX_L3_CSUM;
98c10d12e3SJakub Kicinski } else if (ipv6h->version != 6) {
99c10d12e3SJakub Kicinski nn_dp_warn(dp, "partial checksum but ipv=%x!\n", iph->version);
100c10d12e3SJakub Kicinski return flags;
101c10d12e3SJakub Kicinski }
102c10d12e3SJakub Kicinski
103c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
104c10d12e3SJakub Kicinski if (!skb->encapsulation) {
105c10d12e3SJakub Kicinski r_vec->hw_csum_tx += pkt_cnt;
106c10d12e3SJakub Kicinski } else {
107c10d12e3SJakub Kicinski flags |= NFDK_DESC_TX_ENCAP;
108c10d12e3SJakub Kicinski r_vec->hw_csum_tx_inner += pkt_cnt;
109c10d12e3SJakub Kicinski }
110c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
111c10d12e3SJakub Kicinski
112c10d12e3SJakub Kicinski return flags;
113c10d12e3SJakub Kicinski }
114c10d12e3SJakub Kicinski
115c10d12e3SJakub Kicinski static int
nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring * tx_ring,struct sk_buff * skb)116c10d12e3SJakub Kicinski nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring,
1179c840d5fSBaowen Zheng struct sk_buff *skb)
118c10d12e3SJakub Kicinski {
119c10d12e3SJakub Kicinski unsigned int n_descs, wr_p, nop_slots;
120c10d12e3SJakub Kicinski const skb_frag_t *frag, *fend;
121c10d12e3SJakub Kicinski struct nfp_nfdk_tx_desc *txd;
1229c840d5fSBaowen Zheng unsigned int nr_frags;
123c10d12e3SJakub Kicinski unsigned int wr_idx;
124c10d12e3SJakub Kicinski int err;
125c10d12e3SJakub Kicinski
126c10d12e3SJakub Kicinski recount_descs:
127c10d12e3SJakub Kicinski n_descs = nfp_nfdk_headlen_to_segs(skb_headlen(skb));
1289c840d5fSBaowen Zheng nr_frags = skb_shinfo(skb)->nr_frags;
129c10d12e3SJakub Kicinski frag = skb_shinfo(skb)->frags;
130c10d12e3SJakub Kicinski fend = frag + nr_frags;
131c10d12e3SJakub Kicinski for (; frag < fend; frag++)
132c10d12e3SJakub Kicinski n_descs += DIV_ROUND_UP(skb_frag_size(frag),
133c10d12e3SJakub Kicinski NFDK_TX_MAX_DATA_PER_DESC);
134c10d12e3SJakub Kicinski
135c10d12e3SJakub Kicinski if (unlikely(n_descs > NFDK_TX_DESC_GATHER_MAX)) {
136c10d12e3SJakub Kicinski if (skb_is_nonlinear(skb)) {
137c10d12e3SJakub Kicinski err = skb_linearize(skb);
138c10d12e3SJakub Kicinski if (err)
139c10d12e3SJakub Kicinski return err;
140c10d12e3SJakub Kicinski goto recount_descs;
141c10d12e3SJakub Kicinski }
142c10d12e3SJakub Kicinski return -EINVAL;
143c10d12e3SJakub Kicinski }
144c10d12e3SJakub Kicinski
145c10d12e3SJakub Kicinski /* Under count by 1 (don't count meta) for the round down to work out */
146c10d12e3SJakub Kicinski n_descs += !!skb_is_gso(skb);
147c10d12e3SJakub Kicinski
148c10d12e3SJakub Kicinski if (round_down(tx_ring->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
149c10d12e3SJakub Kicinski round_down(tx_ring->wr_p + n_descs, NFDK_TX_DESC_BLOCK_CNT))
150c10d12e3SJakub Kicinski goto close_block;
151c10d12e3SJakub Kicinski
152c10d12e3SJakub Kicinski if ((u32)tx_ring->data_pending + skb->len > NFDK_TX_MAX_DATA_PER_BLOCK)
153c10d12e3SJakub Kicinski goto close_block;
154c10d12e3SJakub Kicinski
155c10d12e3SJakub Kicinski return 0;
156c10d12e3SJakub Kicinski
157c10d12e3SJakub Kicinski close_block:
158c10d12e3SJakub Kicinski wr_p = tx_ring->wr_p;
159c10d12e3SJakub Kicinski nop_slots = D_BLOCK_CPL(wr_p);
160c10d12e3SJakub Kicinski
161c10d12e3SJakub Kicinski wr_idx = D_IDX(tx_ring, wr_p);
162c10d12e3SJakub Kicinski tx_ring->ktxbufs[wr_idx].skb = NULL;
163c10d12e3SJakub Kicinski txd = &tx_ring->ktxds[wr_idx];
164c10d12e3SJakub Kicinski
165c10d12e3SJakub Kicinski memset(txd, 0, array_size(nop_slots, sizeof(struct nfp_nfdk_tx_desc)));
166c10d12e3SJakub Kicinski
167c10d12e3SJakub Kicinski tx_ring->data_pending = 0;
168c10d12e3SJakub Kicinski tx_ring->wr_p += nop_slots;
169c10d12e3SJakub Kicinski tx_ring->wr_ptr_add += nop_slots;
170c10d12e3SJakub Kicinski
171c10d12e3SJakub Kicinski return 0;
172c10d12e3SJakub Kicinski }
173c10d12e3SJakub Kicinski
174eca250b1SDiana Wang static int
nfp_nfdk_prep_tx_meta(struct nfp_net_dp * dp,struct nfp_app * app,struct sk_buff * skb,bool * ipsec)175eca250b1SDiana Wang nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app,
176436396f2SHuanhuan Wang struct sk_buff *skb, bool *ipsec)
177c10d12e3SJakub Kicinski {
178c10d12e3SJakub Kicinski struct metadata_dst *md_dst = skb_metadata_dst(skb);
179436396f2SHuanhuan Wang struct nfp_ipsec_offload offload_info;
180c10d12e3SJakub Kicinski unsigned char *data;
181eca250b1SDiana Wang bool vlan_insert;
182c10d12e3SJakub Kicinski u32 meta_id = 0;
183eca250b1SDiana Wang int md_bytes;
184c10d12e3SJakub Kicinski
185436396f2SHuanhuan Wang #ifdef CONFIG_NFP_NET_IPSEC
186436396f2SHuanhuan Wang if (xfrm_offload(skb))
187436396f2SHuanhuan Wang *ipsec = nfp_net_ipsec_tx_prep(dp, skb, &offload_info);
188436396f2SHuanhuan Wang #endif
189436396f2SHuanhuan Wang
190eca250b1SDiana Wang if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
191eca250b1SDiana Wang md_dst = NULL;
192c10d12e3SJakub Kicinski
193eca250b1SDiana Wang vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);
194c10d12e3SJakub Kicinski
195436396f2SHuanhuan Wang if (!(md_dst || vlan_insert || *ipsec))
196eca250b1SDiana Wang return 0;
197eca250b1SDiana Wang
198eca250b1SDiana Wang md_bytes = sizeof(meta_id) +
199436396f2SHuanhuan Wang (!!md_dst ? NFP_NET_META_PORTID_SIZE : 0) +
200436396f2SHuanhuan Wang (vlan_insert ? NFP_NET_META_VLAN_SIZE : 0) +
201436396f2SHuanhuan Wang (*ipsec ? NFP_NET_META_IPSEC_FIELD_SIZE : 0);
202eca250b1SDiana Wang
203eca250b1SDiana Wang if (unlikely(skb_cow_head(skb, md_bytes)))
204c10d12e3SJakub Kicinski return -ENOMEM;
205c10d12e3SJakub Kicinski
206eca250b1SDiana Wang data = skb_push(skb, md_bytes) + md_bytes;
207eca250b1SDiana Wang if (md_dst) {
208eca250b1SDiana Wang data -= NFP_NET_META_PORTID_SIZE;
209eca250b1SDiana Wang put_unaligned_be32(md_dst->u.port_info.port_id, data);
210eca250b1SDiana Wang meta_id = NFP_NET_META_PORTID;
211eca250b1SDiana Wang }
212eca250b1SDiana Wang if (vlan_insert) {
213eca250b1SDiana Wang data -= NFP_NET_META_VLAN_SIZE;
214eca250b1SDiana Wang /* data type of skb->vlan_proto is __be16
215eca250b1SDiana Wang * so it fills metadata without calling put_unaligned_be16
216eca250b1SDiana Wang */
217eca250b1SDiana Wang memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto));
218eca250b1SDiana Wang put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto));
219eca250b1SDiana Wang meta_id <<= NFP_NET_META_FIELD_SIZE;
220eca250b1SDiana Wang meta_id |= NFP_NET_META_VLAN;
221eca250b1SDiana Wang }
222c10d12e3SJakub Kicinski
223436396f2SHuanhuan Wang if (*ipsec) {
224436396f2SHuanhuan Wang data -= NFP_NET_META_IPSEC_SIZE;
225436396f2SHuanhuan Wang put_unaligned_be32(offload_info.seq_hi, data);
226436396f2SHuanhuan Wang data -= NFP_NET_META_IPSEC_SIZE;
227436396f2SHuanhuan Wang put_unaligned_be32(offload_info.seq_low, data);
228436396f2SHuanhuan Wang data -= NFP_NET_META_IPSEC_SIZE;
229436396f2SHuanhuan Wang put_unaligned_be32(offload_info.handle - 1, data);
230436396f2SHuanhuan Wang meta_id <<= NFP_NET_META_IPSEC_FIELD_SIZE;
231436396f2SHuanhuan Wang meta_id |= NFP_NET_META_IPSEC << 8 | NFP_NET_META_IPSEC << 4 | NFP_NET_META_IPSEC;
232436396f2SHuanhuan Wang }
233436396f2SHuanhuan Wang
234c10d12e3SJakub Kicinski meta_id = FIELD_PREP(NFDK_META_LEN, md_bytes) |
235c10d12e3SJakub Kicinski FIELD_PREP(NFDK_META_FIELDS, meta_id);
236c10d12e3SJakub Kicinski
237eca250b1SDiana Wang data -= sizeof(meta_id);
238c10d12e3SJakub Kicinski put_unaligned_be32(meta_id, data);
239c10d12e3SJakub Kicinski
240c10d12e3SJakub Kicinski return NFDK_DESC_TX_CHAIN_META;
241c10d12e3SJakub Kicinski }
242c10d12e3SJakub Kicinski
243c10d12e3SJakub Kicinski /**
244c10d12e3SJakub Kicinski * nfp_nfdk_tx() - Main transmit entry point
245c10d12e3SJakub Kicinski * @skb: SKB to transmit
246c10d12e3SJakub Kicinski * @netdev: netdev structure
247c10d12e3SJakub Kicinski *
248c10d12e3SJakub Kicinski * Return: NETDEV_TX_OK on success.
249c10d12e3SJakub Kicinski */
nfp_nfdk_tx(struct sk_buff * skb,struct net_device * netdev)250c10d12e3SJakub Kicinski netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
251c10d12e3SJakub Kicinski {
252c10d12e3SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
253c10d12e3SJakub Kicinski struct nfp_nfdk_tx_buf *txbuf, *etxbuf;
254c10d12e3SJakub Kicinski u32 cnt, tmp_dlen, dlen_type = 0;
255c10d12e3SJakub Kicinski struct nfp_net_tx_ring *tx_ring;
256c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec;
257c10d12e3SJakub Kicinski const skb_frag_t *frag, *fend;
258c10d12e3SJakub Kicinski struct nfp_nfdk_tx_desc *txd;
259c10d12e3SJakub Kicinski unsigned int real_len, qidx;
260c10d12e3SJakub Kicinski unsigned int dma_len, type;
261c10d12e3SJakub Kicinski struct netdev_queue *nd_q;
262c10d12e3SJakub Kicinski struct nfp_net_dp *dp;
263c10d12e3SJakub Kicinski int nr_frags, wr_idx;
264c10d12e3SJakub Kicinski dma_addr_t dma_addr;
265436396f2SHuanhuan Wang bool ipsec = false;
266c10d12e3SJakub Kicinski u64 metadata;
267c10d12e3SJakub Kicinski
268c10d12e3SJakub Kicinski dp = &nn->dp;
269c10d12e3SJakub Kicinski qidx = skb_get_queue_mapping(skb);
270c10d12e3SJakub Kicinski tx_ring = &dp->tx_rings[qidx];
271c10d12e3SJakub Kicinski r_vec = tx_ring->r_vec;
272c10d12e3SJakub Kicinski nd_q = netdev_get_tx_queue(dp->netdev, qidx);
273c10d12e3SJakub Kicinski
274c10d12e3SJakub Kicinski /* Don't bother counting frags, assume the worst */
275c10d12e3SJakub Kicinski if (unlikely(nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT))) {
276c10d12e3SJakub Kicinski nn_dp_warn(dp, "TX ring %d busy. wrp=%u rdp=%u\n",
277c10d12e3SJakub Kicinski qidx, tx_ring->wr_p, tx_ring->rd_p);
278c10d12e3SJakub Kicinski netif_tx_stop_queue(nd_q);
279c10d12e3SJakub Kicinski nfp_net_tx_xmit_more_flush(tx_ring);
280c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
281c10d12e3SJakub Kicinski r_vec->tx_busy++;
282c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
283c10d12e3SJakub Kicinski return NETDEV_TX_BUSY;
284c10d12e3SJakub Kicinski }
285c10d12e3SJakub Kicinski
286436396f2SHuanhuan Wang metadata = nfp_nfdk_prep_tx_meta(dp, nn->app, skb, &ipsec);
287c10d12e3SJakub Kicinski if (unlikely((int)metadata < 0))
288c10d12e3SJakub Kicinski goto err_flush;
289c10d12e3SJakub Kicinski
2909c840d5fSBaowen Zheng if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
291c10d12e3SJakub Kicinski goto err_flush;
292c10d12e3SJakub Kicinski
2939c840d5fSBaowen Zheng /* nr_frags will change after skb_linearize so we get nr_frags after
2949c840d5fSBaowen Zheng * nfp_nfdk_tx_maybe_close_block function
2959c840d5fSBaowen Zheng */
2969c840d5fSBaowen Zheng nr_frags = skb_shinfo(skb)->nr_frags;
297c10d12e3SJakub Kicinski /* DMA map all */
298c10d12e3SJakub Kicinski wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
299c10d12e3SJakub Kicinski txd = &tx_ring->ktxds[wr_idx];
300c10d12e3SJakub Kicinski txbuf = &tx_ring->ktxbufs[wr_idx];
301c10d12e3SJakub Kicinski
302c10d12e3SJakub Kicinski dma_len = skb_headlen(skb);
303c10d12e3SJakub Kicinski if (skb_is_gso(skb))
304c10d12e3SJakub Kicinski type = NFDK_DESC_TX_TYPE_TSO;
3055c306de8SYinjun Zhang else if (!nr_frags && dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
306c10d12e3SJakub Kicinski type = NFDK_DESC_TX_TYPE_SIMPLE;
307c10d12e3SJakub Kicinski else
308c10d12e3SJakub Kicinski type = NFDK_DESC_TX_TYPE_GATHER;
309c10d12e3SJakub Kicinski
310c10d12e3SJakub Kicinski dma_addr = dma_map_single(dp->dev, skb->data, dma_len, DMA_TO_DEVICE);
311c10d12e3SJakub Kicinski if (dma_mapping_error(dp->dev, dma_addr))
312c10d12e3SJakub Kicinski goto err_warn_dma;
313c10d12e3SJakub Kicinski
314c10d12e3SJakub Kicinski txbuf->skb = skb;
315c10d12e3SJakub Kicinski txbuf++;
316c10d12e3SJakub Kicinski
317c10d12e3SJakub Kicinski txbuf->dma_addr = dma_addr;
318c10d12e3SJakub Kicinski txbuf++;
319c10d12e3SJakub Kicinski
320c10d12e3SJakub Kicinski /* FIELD_PREP() implicitly truncates to chunk */
321c10d12e3SJakub Kicinski dma_len -= 1;
3229c840d5fSBaowen Zheng
3239c840d5fSBaowen Zheng /* We will do our best to pass as much data as we can in descriptor
3249c840d5fSBaowen Zheng * and we need to make sure the first descriptor includes whole head
3259c840d5fSBaowen Zheng * since there is limitation in firmware side. Sometimes the value of
3269c840d5fSBaowen Zheng * dma_len bitwise and NFDK_DESC_TX_DMA_LEN_HEAD will less than
3279c840d5fSBaowen Zheng * headlen.
3289c840d5fSBaowen Zheng */
3299c840d5fSBaowen Zheng dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
3309c840d5fSBaowen Zheng dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
3319c840d5fSBaowen Zheng NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
332c10d12e3SJakub Kicinski FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
333c10d12e3SJakub Kicinski
334c10d12e3SJakub Kicinski txd->dma_len_type = cpu_to_le16(dlen_type);
3355f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
336c10d12e3SJakub Kicinski
337c10d12e3SJakub Kicinski /* starts at bit 0 */
338c10d12e3SJakub Kicinski BUILD_BUG_ON(!(NFDK_DESC_TX_DMA_LEN_HEAD & 1));
339c10d12e3SJakub Kicinski
340c10d12e3SJakub Kicinski /* Preserve the original dlen_type, this way below the EOP logic
341c10d12e3SJakub Kicinski * can use dlen_type.
342c10d12e3SJakub Kicinski */
343c10d12e3SJakub Kicinski tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
344c10d12e3SJakub Kicinski dma_len -= tmp_dlen;
345c10d12e3SJakub Kicinski dma_addr += tmp_dlen + 1;
346c10d12e3SJakub Kicinski txd++;
347c10d12e3SJakub Kicinski
348c10d12e3SJakub Kicinski /* The rest of the data (if any) will be in larger dma descritors
349c10d12e3SJakub Kicinski * and is handled with the fragment loop.
350c10d12e3SJakub Kicinski */
351c10d12e3SJakub Kicinski frag = skb_shinfo(skb)->frags;
352c10d12e3SJakub Kicinski fend = frag + nr_frags;
353c10d12e3SJakub Kicinski
354c10d12e3SJakub Kicinski while (true) {
355c10d12e3SJakub Kicinski while (dma_len > 0) {
356c10d12e3SJakub Kicinski dma_len -= 1;
357c10d12e3SJakub Kicinski dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
358c10d12e3SJakub Kicinski
359c10d12e3SJakub Kicinski txd->dma_len_type = cpu_to_le16(dlen_type);
3605f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
361c10d12e3SJakub Kicinski
362c10d12e3SJakub Kicinski dma_len -= dlen_type;
363c10d12e3SJakub Kicinski dma_addr += dlen_type + 1;
364c10d12e3SJakub Kicinski txd++;
365c10d12e3SJakub Kicinski }
366c10d12e3SJakub Kicinski
367c10d12e3SJakub Kicinski if (frag >= fend)
368c10d12e3SJakub Kicinski break;
369c10d12e3SJakub Kicinski
370c10d12e3SJakub Kicinski dma_len = skb_frag_size(frag);
371c10d12e3SJakub Kicinski dma_addr = skb_frag_dma_map(dp->dev, frag, 0, dma_len,
372c10d12e3SJakub Kicinski DMA_TO_DEVICE);
373c10d12e3SJakub Kicinski if (dma_mapping_error(dp->dev, dma_addr))
374c10d12e3SJakub Kicinski goto err_unmap;
375c10d12e3SJakub Kicinski
376c10d12e3SJakub Kicinski txbuf->dma_addr = dma_addr;
377c10d12e3SJakub Kicinski txbuf++;
378c10d12e3SJakub Kicinski
379c10d12e3SJakub Kicinski frag++;
380c10d12e3SJakub Kicinski }
381c10d12e3SJakub Kicinski
382c10d12e3SJakub Kicinski (txd - 1)->dma_len_type = cpu_to_le16(dlen_type | NFDK_DESC_TX_EOP);
383c10d12e3SJakub Kicinski
384436396f2SHuanhuan Wang if (ipsec)
385436396f2SHuanhuan Wang metadata = nfp_nfdk_ipsec_tx(metadata, skb);
386436396f2SHuanhuan Wang
387c10d12e3SJakub Kicinski if (!skb_is_gso(skb)) {
388c10d12e3SJakub Kicinski real_len = skb->len;
389c10d12e3SJakub Kicinski /* Metadata desc */
390*8b46168cSHuanhuan Wang if (!ipsec)
391c10d12e3SJakub Kicinski metadata = nfp_nfdk_tx_csum(dp, r_vec, 1, skb, metadata);
392c10d12e3SJakub Kicinski txd->raw = cpu_to_le64(metadata);
393c10d12e3SJakub Kicinski txd++;
394c10d12e3SJakub Kicinski } else {
395c10d12e3SJakub Kicinski /* lso desc should be placed after metadata desc */
396c10d12e3SJakub Kicinski (txd + 1)->raw = nfp_nfdk_tx_tso(r_vec, txbuf, skb);
397c10d12e3SJakub Kicinski real_len = txbuf->real_len;
398c10d12e3SJakub Kicinski /* Metadata desc */
399*8b46168cSHuanhuan Wang if (!ipsec)
400c10d12e3SJakub Kicinski metadata = nfp_nfdk_tx_csum(dp, r_vec, txbuf->pkt_cnt, skb, metadata);
401c10d12e3SJakub Kicinski txd->raw = cpu_to_le64(metadata);
402c10d12e3SJakub Kicinski txd += 2;
403c10d12e3SJakub Kicinski txbuf++;
404c10d12e3SJakub Kicinski }
405c10d12e3SJakub Kicinski
406c10d12e3SJakub Kicinski cnt = txd - tx_ring->ktxds - wr_idx;
407c10d12e3SJakub Kicinski if (unlikely(round_down(wr_idx, NFDK_TX_DESC_BLOCK_CNT) !=
408c10d12e3SJakub Kicinski round_down(wr_idx + cnt - 1, NFDK_TX_DESC_BLOCK_CNT)))
409c10d12e3SJakub Kicinski goto err_warn_overflow;
410c10d12e3SJakub Kicinski
411c10d12e3SJakub Kicinski skb_tx_timestamp(skb);
412c10d12e3SJakub Kicinski
413c10d12e3SJakub Kicinski tx_ring->wr_p += cnt;
414c10d12e3SJakub Kicinski if (tx_ring->wr_p % NFDK_TX_DESC_BLOCK_CNT)
415c10d12e3SJakub Kicinski tx_ring->data_pending += skb->len;
416c10d12e3SJakub Kicinski else
417c10d12e3SJakub Kicinski tx_ring->data_pending = 0;
418c10d12e3SJakub Kicinski
419c10d12e3SJakub Kicinski if (nfp_nfdk_tx_ring_should_stop(tx_ring))
420c10d12e3SJakub Kicinski nfp_nfdk_tx_ring_stop(nd_q, tx_ring);
421c10d12e3SJakub Kicinski
422c10d12e3SJakub Kicinski tx_ring->wr_ptr_add += cnt;
423c10d12e3SJakub Kicinski if (__netdev_tx_sent_queue(nd_q, real_len, netdev_xmit_more()))
424c10d12e3SJakub Kicinski nfp_net_tx_xmit_more_flush(tx_ring);
425c10d12e3SJakub Kicinski
426c10d12e3SJakub Kicinski return NETDEV_TX_OK;
427c10d12e3SJakub Kicinski
428c10d12e3SJakub Kicinski err_warn_overflow:
429c10d12e3SJakub Kicinski WARN_ONCE(1, "unable to fit packet into a descriptor wr_idx:%d head:%d frags:%d cnt:%d",
430c10d12e3SJakub Kicinski wr_idx, skb_headlen(skb), nr_frags, cnt);
431c10d12e3SJakub Kicinski if (skb_is_gso(skb))
432c10d12e3SJakub Kicinski txbuf--;
433c10d12e3SJakub Kicinski err_unmap:
434c10d12e3SJakub Kicinski /* txbuf pointed to the next-to-use */
435c10d12e3SJakub Kicinski etxbuf = txbuf;
436c10d12e3SJakub Kicinski /* first txbuf holds the skb */
437c10d12e3SJakub Kicinski txbuf = &tx_ring->ktxbufs[wr_idx + 1];
438c10d12e3SJakub Kicinski if (txbuf < etxbuf) {
439c10d12e3SJakub Kicinski dma_unmap_single(dp->dev, txbuf->dma_addr,
440c10d12e3SJakub Kicinski skb_headlen(skb), DMA_TO_DEVICE);
441c10d12e3SJakub Kicinski txbuf->raw = 0;
442c10d12e3SJakub Kicinski txbuf++;
443c10d12e3SJakub Kicinski }
444c10d12e3SJakub Kicinski frag = skb_shinfo(skb)->frags;
445c10d12e3SJakub Kicinski while (etxbuf < txbuf) {
446c10d12e3SJakub Kicinski dma_unmap_page(dp->dev, txbuf->dma_addr,
447c10d12e3SJakub Kicinski skb_frag_size(frag), DMA_TO_DEVICE);
448c10d12e3SJakub Kicinski txbuf->raw = 0;
449c10d12e3SJakub Kicinski frag++;
450c10d12e3SJakub Kicinski txbuf++;
451c10d12e3SJakub Kicinski }
452c10d12e3SJakub Kicinski err_warn_dma:
453c10d12e3SJakub Kicinski nn_dp_warn(dp, "Failed to map DMA TX buffer\n");
454c10d12e3SJakub Kicinski err_flush:
455c10d12e3SJakub Kicinski nfp_net_tx_xmit_more_flush(tx_ring);
456c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
457c10d12e3SJakub Kicinski r_vec->tx_errors++;
458c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
459c10d12e3SJakub Kicinski dev_kfree_skb_any(skb);
460c10d12e3SJakub Kicinski return NETDEV_TX_OK;
461c10d12e3SJakub Kicinski }
462c10d12e3SJakub Kicinski
463c10d12e3SJakub Kicinski /**
464c10d12e3SJakub Kicinski * nfp_nfdk_tx_complete() - Handled completed TX packets
465c10d12e3SJakub Kicinski * @tx_ring: TX ring structure
466c10d12e3SJakub Kicinski * @budget: NAPI budget (only used as bool to determine if in NAPI context)
467c10d12e3SJakub Kicinski */
nfp_nfdk_tx_complete(struct nfp_net_tx_ring * tx_ring,int budget)468c10d12e3SJakub Kicinski static void nfp_nfdk_tx_complete(struct nfp_net_tx_ring *tx_ring, int budget)
469c10d12e3SJakub Kicinski {
470c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec = tx_ring->r_vec;
471c10d12e3SJakub Kicinski struct nfp_net_dp *dp = &r_vec->nfp_net->dp;
472c10d12e3SJakub Kicinski u32 done_pkts = 0, done_bytes = 0;
473c10d12e3SJakub Kicinski struct nfp_nfdk_tx_buf *ktxbufs;
474c10d12e3SJakub Kicinski struct device *dev = dp->dev;
475c10d12e3SJakub Kicinski struct netdev_queue *nd_q;
476c10d12e3SJakub Kicinski u32 rd_p, qcp_rd_p;
477c10d12e3SJakub Kicinski int todo;
478c10d12e3SJakub Kicinski
479c10d12e3SJakub Kicinski rd_p = tx_ring->rd_p;
480c10d12e3SJakub Kicinski if (tx_ring->wr_p == rd_p)
481c10d12e3SJakub Kicinski return;
482c10d12e3SJakub Kicinski
483c10d12e3SJakub Kicinski /* Work out how many descriptors have been transmitted */
484c10d12e3SJakub Kicinski qcp_rd_p = nfp_net_read_tx_cmpl(tx_ring, dp);
485c10d12e3SJakub Kicinski
486c10d12e3SJakub Kicinski if (qcp_rd_p == tx_ring->qcp_rd_p)
487c10d12e3SJakub Kicinski return;
488c10d12e3SJakub Kicinski
489c10d12e3SJakub Kicinski todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p);
490c10d12e3SJakub Kicinski ktxbufs = tx_ring->ktxbufs;
491c10d12e3SJakub Kicinski
492c10d12e3SJakub Kicinski while (todo > 0) {
493c10d12e3SJakub Kicinski const skb_frag_t *frag, *fend;
494c10d12e3SJakub Kicinski unsigned int size, n_descs = 1;
495c10d12e3SJakub Kicinski struct nfp_nfdk_tx_buf *txbuf;
496c10d12e3SJakub Kicinski struct sk_buff *skb;
497c10d12e3SJakub Kicinski
498c10d12e3SJakub Kicinski txbuf = &ktxbufs[D_IDX(tx_ring, rd_p)];
499c10d12e3SJakub Kicinski skb = txbuf->skb;
500c10d12e3SJakub Kicinski txbuf++;
501c10d12e3SJakub Kicinski
502c10d12e3SJakub Kicinski /* Closed block */
503c10d12e3SJakub Kicinski if (!skb) {
504c10d12e3SJakub Kicinski n_descs = D_BLOCK_CPL(rd_p);
505c10d12e3SJakub Kicinski goto next;
506c10d12e3SJakub Kicinski }
507c10d12e3SJakub Kicinski
508c10d12e3SJakub Kicinski /* Unmap head */
509c10d12e3SJakub Kicinski size = skb_headlen(skb);
510c10d12e3SJakub Kicinski n_descs += nfp_nfdk_headlen_to_segs(size);
511c10d12e3SJakub Kicinski dma_unmap_single(dev, txbuf->dma_addr, size, DMA_TO_DEVICE);
512c10d12e3SJakub Kicinski txbuf++;
513c10d12e3SJakub Kicinski
514c10d12e3SJakub Kicinski /* Unmap frags */
515c10d12e3SJakub Kicinski frag = skb_shinfo(skb)->frags;
516c10d12e3SJakub Kicinski fend = frag + skb_shinfo(skb)->nr_frags;
517c10d12e3SJakub Kicinski for (; frag < fend; frag++) {
518c10d12e3SJakub Kicinski size = skb_frag_size(frag);
519c10d12e3SJakub Kicinski n_descs += DIV_ROUND_UP(size,
520c10d12e3SJakub Kicinski NFDK_TX_MAX_DATA_PER_DESC);
521c10d12e3SJakub Kicinski dma_unmap_page(dev, txbuf->dma_addr,
522c10d12e3SJakub Kicinski skb_frag_size(frag), DMA_TO_DEVICE);
523c10d12e3SJakub Kicinski txbuf++;
524c10d12e3SJakub Kicinski }
525c10d12e3SJakub Kicinski
526c10d12e3SJakub Kicinski if (!skb_is_gso(skb)) {
527c10d12e3SJakub Kicinski done_bytes += skb->len;
528c10d12e3SJakub Kicinski done_pkts++;
529c10d12e3SJakub Kicinski } else {
530c10d12e3SJakub Kicinski done_bytes += txbuf->real_len;
531c10d12e3SJakub Kicinski done_pkts += txbuf->pkt_cnt;
532c10d12e3SJakub Kicinski n_descs++;
533c10d12e3SJakub Kicinski }
534c10d12e3SJakub Kicinski
535c10d12e3SJakub Kicinski napi_consume_skb(skb, budget);
536c10d12e3SJakub Kicinski next:
537c10d12e3SJakub Kicinski rd_p += n_descs;
538c10d12e3SJakub Kicinski todo -= n_descs;
539c10d12e3SJakub Kicinski }
540c10d12e3SJakub Kicinski
541c10d12e3SJakub Kicinski tx_ring->rd_p = rd_p;
542c10d12e3SJakub Kicinski tx_ring->qcp_rd_p = qcp_rd_p;
543c10d12e3SJakub Kicinski
544c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
545c10d12e3SJakub Kicinski r_vec->tx_bytes += done_bytes;
546c10d12e3SJakub Kicinski r_vec->tx_pkts += done_pkts;
547c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
548c10d12e3SJakub Kicinski
549c10d12e3SJakub Kicinski if (!dp->netdev)
550c10d12e3SJakub Kicinski return;
551c10d12e3SJakub Kicinski
552c10d12e3SJakub Kicinski nd_q = netdev_get_tx_queue(dp->netdev, tx_ring->idx);
553c10d12e3SJakub Kicinski netdev_tx_completed_queue(nd_q, done_pkts, done_bytes);
554c10d12e3SJakub Kicinski if (nfp_nfdk_tx_ring_should_wake(tx_ring)) {
555c10d12e3SJakub Kicinski /* Make sure TX thread will see updated tx_ring->rd_p */
556c10d12e3SJakub Kicinski smp_mb();
557c10d12e3SJakub Kicinski
558c10d12e3SJakub Kicinski if (unlikely(netif_tx_queue_stopped(nd_q)))
559c10d12e3SJakub Kicinski netif_tx_wake_queue(nd_q);
560c10d12e3SJakub Kicinski }
561c10d12e3SJakub Kicinski
562c10d12e3SJakub Kicinski WARN_ONCE(tx_ring->wr_p - tx_ring->rd_p > tx_ring->cnt,
563c10d12e3SJakub Kicinski "TX ring corruption rd_p=%u wr_p=%u cnt=%u\n",
564c10d12e3SJakub Kicinski tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt);
565c10d12e3SJakub Kicinski }
566c10d12e3SJakub Kicinski
567c10d12e3SJakub Kicinski /* Receive processing */
568c10d12e3SJakub Kicinski static void *
nfp_nfdk_napi_alloc_one(struct nfp_net_dp * dp,dma_addr_t * dma_addr)569c10d12e3SJakub Kicinski nfp_nfdk_napi_alloc_one(struct nfp_net_dp *dp, dma_addr_t *dma_addr)
570c10d12e3SJakub Kicinski {
571c10d12e3SJakub Kicinski void *frag;
572c10d12e3SJakub Kicinski
573c10d12e3SJakub Kicinski if (!dp->xdp_prog) {
574c10d12e3SJakub Kicinski frag = napi_alloc_frag(dp->fl_bufsz);
575c10d12e3SJakub Kicinski if (unlikely(!frag))
576c10d12e3SJakub Kicinski return NULL;
577c10d12e3SJakub Kicinski } else {
578c10d12e3SJakub Kicinski struct page *page;
579c10d12e3SJakub Kicinski
580c10d12e3SJakub Kicinski page = dev_alloc_page();
581c10d12e3SJakub Kicinski if (unlikely(!page))
582c10d12e3SJakub Kicinski return NULL;
583c10d12e3SJakub Kicinski frag = page_address(page);
584c10d12e3SJakub Kicinski }
585c10d12e3SJakub Kicinski
586c10d12e3SJakub Kicinski *dma_addr = nfp_net_dma_map_rx(dp, frag);
587c10d12e3SJakub Kicinski if (dma_mapping_error(dp->dev, *dma_addr)) {
588c10d12e3SJakub Kicinski nfp_net_free_frag(frag, dp->xdp_prog);
589c10d12e3SJakub Kicinski nn_dp_warn(dp, "Failed to map DMA RX buffer\n");
590c10d12e3SJakub Kicinski return NULL;
591c10d12e3SJakub Kicinski }
592c10d12e3SJakub Kicinski
593c10d12e3SJakub Kicinski return frag;
594c10d12e3SJakub Kicinski }
595c10d12e3SJakub Kicinski
596c10d12e3SJakub Kicinski /**
597c10d12e3SJakub Kicinski * nfp_nfdk_rx_give_one() - Put mapped skb on the software and hardware rings
598c10d12e3SJakub Kicinski * @dp: NFP Net data path struct
599c10d12e3SJakub Kicinski * @rx_ring: RX ring structure
600c10d12e3SJakub Kicinski * @frag: page fragment buffer
601c10d12e3SJakub Kicinski * @dma_addr: DMA address of skb mapping
602c10d12e3SJakub Kicinski */
603c10d12e3SJakub Kicinski static void
nfp_nfdk_rx_give_one(const struct nfp_net_dp * dp,struct nfp_net_rx_ring * rx_ring,void * frag,dma_addr_t dma_addr)604c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(const struct nfp_net_dp *dp,
605c10d12e3SJakub Kicinski struct nfp_net_rx_ring *rx_ring,
606c10d12e3SJakub Kicinski void *frag, dma_addr_t dma_addr)
607c10d12e3SJakub Kicinski {
608c10d12e3SJakub Kicinski unsigned int wr_idx;
609c10d12e3SJakub Kicinski
610c10d12e3SJakub Kicinski wr_idx = D_IDX(rx_ring, rx_ring->wr_p);
611c10d12e3SJakub Kicinski
612c10d12e3SJakub Kicinski nfp_net_dma_sync_dev_rx(dp, dma_addr);
613c10d12e3SJakub Kicinski
614c10d12e3SJakub Kicinski /* Stash SKB and DMA address away */
615c10d12e3SJakub Kicinski rx_ring->rxbufs[wr_idx].frag = frag;
616c10d12e3SJakub Kicinski rx_ring->rxbufs[wr_idx].dma_addr = dma_addr;
617c10d12e3SJakub Kicinski
618c10d12e3SJakub Kicinski /* Fill freelist descriptor */
619c10d12e3SJakub Kicinski rx_ring->rxds[wr_idx].fld.reserved = 0;
620c10d12e3SJakub Kicinski rx_ring->rxds[wr_idx].fld.meta_len_dd = 0;
6215f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld,
622c10d12e3SJakub Kicinski dma_addr + dp->rx_dma_off);
623c10d12e3SJakub Kicinski
624c10d12e3SJakub Kicinski rx_ring->wr_p++;
625c10d12e3SJakub Kicinski if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) {
626c10d12e3SJakub Kicinski /* Update write pointer of the freelist queue. Make
627c10d12e3SJakub Kicinski * sure all writes are flushed before telling the hardware.
628c10d12e3SJakub Kicinski */
629c10d12e3SJakub Kicinski wmb();
630c10d12e3SJakub Kicinski nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, NFP_NET_FL_BATCH);
631c10d12e3SJakub Kicinski }
632c10d12e3SJakub Kicinski }
633c10d12e3SJakub Kicinski
634c10d12e3SJakub Kicinski /**
635c10d12e3SJakub Kicinski * nfp_nfdk_rx_ring_fill_freelist() - Give buffers from the ring to FW
636c10d12e3SJakub Kicinski * @dp: NFP Net data path struct
637c10d12e3SJakub Kicinski * @rx_ring: RX ring to fill
638c10d12e3SJakub Kicinski */
nfp_nfdk_rx_ring_fill_freelist(struct nfp_net_dp * dp,struct nfp_net_rx_ring * rx_ring)639c10d12e3SJakub Kicinski void nfp_nfdk_rx_ring_fill_freelist(struct nfp_net_dp *dp,
640c10d12e3SJakub Kicinski struct nfp_net_rx_ring *rx_ring)
641c10d12e3SJakub Kicinski {
642c10d12e3SJakub Kicinski unsigned int i;
643c10d12e3SJakub Kicinski
644c10d12e3SJakub Kicinski for (i = 0; i < rx_ring->cnt - 1; i++)
645c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, rx_ring->rxbufs[i].frag,
646c10d12e3SJakub Kicinski rx_ring->rxbufs[i].dma_addr);
647c10d12e3SJakub Kicinski }
648c10d12e3SJakub Kicinski
649c10d12e3SJakub Kicinski /**
650c10d12e3SJakub Kicinski * nfp_nfdk_rx_csum_has_errors() - group check if rxd has any csum errors
651c10d12e3SJakub Kicinski * @flags: RX descriptor flags field in CPU byte order
652c10d12e3SJakub Kicinski */
nfp_nfdk_rx_csum_has_errors(u16 flags)653c10d12e3SJakub Kicinski static int nfp_nfdk_rx_csum_has_errors(u16 flags)
654c10d12e3SJakub Kicinski {
655c10d12e3SJakub Kicinski u16 csum_all_checked, csum_all_ok;
656c10d12e3SJakub Kicinski
657c10d12e3SJakub Kicinski csum_all_checked = flags & __PCIE_DESC_RX_CSUM_ALL;
658c10d12e3SJakub Kicinski csum_all_ok = flags & __PCIE_DESC_RX_CSUM_ALL_OK;
659c10d12e3SJakub Kicinski
660c10d12e3SJakub Kicinski return csum_all_checked != (csum_all_ok << PCIE_DESC_RX_CSUM_OK_SHIFT);
661c10d12e3SJakub Kicinski }
662c10d12e3SJakub Kicinski
663c10d12e3SJakub Kicinski /**
664c10d12e3SJakub Kicinski * nfp_nfdk_rx_csum() - set SKB checksum field based on RX descriptor flags
665c10d12e3SJakub Kicinski * @dp: NFP Net data path struct
666c10d12e3SJakub Kicinski * @r_vec: per-ring structure
667c10d12e3SJakub Kicinski * @rxd: Pointer to RX descriptor
668c10d12e3SJakub Kicinski * @meta: Parsed metadata prepend
669c10d12e3SJakub Kicinski * @skb: Pointer to SKB
670c10d12e3SJakub Kicinski */
671c10d12e3SJakub Kicinski static void
nfp_nfdk_rx_csum(struct nfp_net_dp * dp,struct nfp_net_r_vector * r_vec,struct nfp_net_rx_desc * rxd,struct nfp_meta_parsed * meta,struct sk_buff * skb)672c10d12e3SJakub Kicinski nfp_nfdk_rx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
673c10d12e3SJakub Kicinski struct nfp_net_rx_desc *rxd, struct nfp_meta_parsed *meta,
674c10d12e3SJakub Kicinski struct sk_buff *skb)
675c10d12e3SJakub Kicinski {
676c10d12e3SJakub Kicinski skb_checksum_none_assert(skb);
677c10d12e3SJakub Kicinski
678c10d12e3SJakub Kicinski if (!(dp->netdev->features & NETIF_F_RXCSUM))
679c10d12e3SJakub Kicinski return;
680c10d12e3SJakub Kicinski
681c10d12e3SJakub Kicinski if (meta->csum_type) {
682c10d12e3SJakub Kicinski skb->ip_summed = meta->csum_type;
683c10d12e3SJakub Kicinski skb->csum = meta->csum;
684c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
685c10d12e3SJakub Kicinski r_vec->hw_csum_rx_complete++;
686c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
687c10d12e3SJakub Kicinski return;
688c10d12e3SJakub Kicinski }
689c10d12e3SJakub Kicinski
690c10d12e3SJakub Kicinski if (nfp_nfdk_rx_csum_has_errors(le16_to_cpu(rxd->rxd.flags))) {
691c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
692c10d12e3SJakub Kicinski r_vec->hw_csum_rx_error++;
693c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
694c10d12e3SJakub Kicinski return;
695c10d12e3SJakub Kicinski }
696c10d12e3SJakub Kicinski
697c10d12e3SJakub Kicinski /* Assume that the firmware will never report inner CSUM_OK unless outer
698c10d12e3SJakub Kicinski * L4 headers were successfully parsed. FW will always report zero UDP
699c10d12e3SJakub Kicinski * checksum as CSUM_OK.
700c10d12e3SJakub Kicinski */
701c10d12e3SJakub Kicinski if (rxd->rxd.flags & PCIE_DESC_RX_TCP_CSUM_OK ||
702c10d12e3SJakub Kicinski rxd->rxd.flags & PCIE_DESC_RX_UDP_CSUM_OK) {
703c10d12e3SJakub Kicinski __skb_incr_checksum_unnecessary(skb);
704c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
705c10d12e3SJakub Kicinski r_vec->hw_csum_rx_ok++;
706c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
707c10d12e3SJakub Kicinski }
708c10d12e3SJakub Kicinski
709c10d12e3SJakub Kicinski if (rxd->rxd.flags & PCIE_DESC_RX_I_TCP_CSUM_OK ||
710c10d12e3SJakub Kicinski rxd->rxd.flags & PCIE_DESC_RX_I_UDP_CSUM_OK) {
711c10d12e3SJakub Kicinski __skb_incr_checksum_unnecessary(skb);
712c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
713c10d12e3SJakub Kicinski r_vec->hw_csum_rx_inner_ok++;
714c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
715c10d12e3SJakub Kicinski }
716c10d12e3SJakub Kicinski }
717c10d12e3SJakub Kicinski
718c10d12e3SJakub Kicinski static void
nfp_nfdk_set_hash(struct net_device * netdev,struct nfp_meta_parsed * meta,unsigned int type,__be32 * hash)719c10d12e3SJakub Kicinski nfp_nfdk_set_hash(struct net_device *netdev, struct nfp_meta_parsed *meta,
720c10d12e3SJakub Kicinski unsigned int type, __be32 *hash)
721c10d12e3SJakub Kicinski {
722c10d12e3SJakub Kicinski if (!(netdev->features & NETIF_F_RXHASH))
723c10d12e3SJakub Kicinski return;
724c10d12e3SJakub Kicinski
725c10d12e3SJakub Kicinski switch (type) {
726c10d12e3SJakub Kicinski case NFP_NET_RSS_IPV4:
727c10d12e3SJakub Kicinski case NFP_NET_RSS_IPV6:
728c10d12e3SJakub Kicinski case NFP_NET_RSS_IPV6_EX:
729c10d12e3SJakub Kicinski meta->hash_type = PKT_HASH_TYPE_L3;
730c10d12e3SJakub Kicinski break;
731c10d12e3SJakub Kicinski default:
732c10d12e3SJakub Kicinski meta->hash_type = PKT_HASH_TYPE_L4;
733c10d12e3SJakub Kicinski break;
734c10d12e3SJakub Kicinski }
735c10d12e3SJakub Kicinski
736c10d12e3SJakub Kicinski meta->hash = get_unaligned_be32(hash);
737c10d12e3SJakub Kicinski }
738c10d12e3SJakub Kicinski
739c10d12e3SJakub Kicinski static bool
nfp_nfdk_parse_meta(struct net_device * netdev,struct nfp_meta_parsed * meta,void * data,void * pkt,unsigned int pkt_len,int meta_len)740c10d12e3SJakub Kicinski nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
741c10d12e3SJakub Kicinski void *data, void *pkt, unsigned int pkt_len, int meta_len)
742c10d12e3SJakub Kicinski {
74367d2656bSDiana Wang u32 meta_info, vlan_info;
744c10d12e3SJakub Kicinski
745c10d12e3SJakub Kicinski meta_info = get_unaligned_be32(data);
746c10d12e3SJakub Kicinski data += 4;
747c10d12e3SJakub Kicinski
748c10d12e3SJakub Kicinski while (meta_info) {
749c10d12e3SJakub Kicinski switch (meta_info & NFP_NET_META_FIELD_MASK) {
750c10d12e3SJakub Kicinski case NFP_NET_META_HASH:
751c10d12e3SJakub Kicinski meta_info >>= NFP_NET_META_FIELD_SIZE;
752c10d12e3SJakub Kicinski nfp_nfdk_set_hash(netdev, meta,
753c10d12e3SJakub Kicinski meta_info & NFP_NET_META_FIELD_MASK,
754c10d12e3SJakub Kicinski (__be32 *)data);
755c10d12e3SJakub Kicinski data += 4;
756c10d12e3SJakub Kicinski break;
757c10d12e3SJakub Kicinski case NFP_NET_META_MARK:
758c10d12e3SJakub Kicinski meta->mark = get_unaligned_be32(data);
759c10d12e3SJakub Kicinski data += 4;
760c10d12e3SJakub Kicinski break;
76167d2656bSDiana Wang case NFP_NET_META_VLAN:
76267d2656bSDiana Wang vlan_info = get_unaligned_be32(data);
76367d2656bSDiana Wang if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
76467d2656bSDiana Wang meta->vlan.stripped = true;
76567d2656bSDiana Wang meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
76667d2656bSDiana Wang vlan_info);
76767d2656bSDiana Wang meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
76867d2656bSDiana Wang vlan_info);
76967d2656bSDiana Wang }
77067d2656bSDiana Wang data += 4;
77167d2656bSDiana Wang break;
772c10d12e3SJakub Kicinski case NFP_NET_META_PORTID:
773c10d12e3SJakub Kicinski meta->portid = get_unaligned_be32(data);
774c10d12e3SJakub Kicinski data += 4;
775c10d12e3SJakub Kicinski break;
776c10d12e3SJakub Kicinski case NFP_NET_META_CSUM:
777c10d12e3SJakub Kicinski meta->csum_type = CHECKSUM_COMPLETE;
778c10d12e3SJakub Kicinski meta->csum =
779c10d12e3SJakub Kicinski (__force __wsum)__get_unaligned_cpu32(data);
780c10d12e3SJakub Kicinski data += 4;
781c10d12e3SJakub Kicinski break;
782c10d12e3SJakub Kicinski case NFP_NET_META_RESYNC_INFO:
783c10d12e3SJakub Kicinski if (nfp_net_tls_rx_resync_req(netdev, data, pkt,
784c10d12e3SJakub Kicinski pkt_len))
785c10d12e3SJakub Kicinski return false;
786c10d12e3SJakub Kicinski data += sizeof(struct nfp_net_tls_resync_req);
787c10d12e3SJakub Kicinski break;
788436396f2SHuanhuan Wang #ifdef CONFIG_NFP_NET_IPSEC
789436396f2SHuanhuan Wang case NFP_NET_META_IPSEC:
790436396f2SHuanhuan Wang /* Note: IPsec packet could have zero saidx, so need add 1
791436396f2SHuanhuan Wang * to indicate packet is IPsec packet within driver.
792436396f2SHuanhuan Wang */
793436396f2SHuanhuan Wang meta->ipsec_saidx = get_unaligned_be32(data) + 1;
794436396f2SHuanhuan Wang data += 4;
795436396f2SHuanhuan Wang break;
796436396f2SHuanhuan Wang #endif
797c10d12e3SJakub Kicinski default:
798c10d12e3SJakub Kicinski return true;
799c10d12e3SJakub Kicinski }
800c10d12e3SJakub Kicinski
801c10d12e3SJakub Kicinski meta_info >>= NFP_NET_META_FIELD_SIZE;
802c10d12e3SJakub Kicinski }
803c10d12e3SJakub Kicinski
804c10d12e3SJakub Kicinski return data != pkt;
805c10d12e3SJakub Kicinski }
806c10d12e3SJakub Kicinski
807c10d12e3SJakub Kicinski static void
nfp_nfdk_rx_drop(const struct nfp_net_dp * dp,struct nfp_net_r_vector * r_vec,struct nfp_net_rx_ring * rx_ring,struct nfp_net_rx_buf * rxbuf,struct sk_buff * skb)808c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(const struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
809c10d12e3SJakub Kicinski struct nfp_net_rx_ring *rx_ring, struct nfp_net_rx_buf *rxbuf,
810c10d12e3SJakub Kicinski struct sk_buff *skb)
811c10d12e3SJakub Kicinski {
812c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
813c10d12e3SJakub Kicinski r_vec->rx_drops++;
814c10d12e3SJakub Kicinski /* If we have both skb and rxbuf the replacement buffer allocation
815c10d12e3SJakub Kicinski * must have failed, count this as an alloc failure.
816c10d12e3SJakub Kicinski */
817c10d12e3SJakub Kicinski if (skb && rxbuf)
818c10d12e3SJakub Kicinski r_vec->rx_replace_buf_alloc_fail++;
819c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
820c10d12e3SJakub Kicinski
821c10d12e3SJakub Kicinski /* skb is build based on the frag, free_skb() would free the frag
822c10d12e3SJakub Kicinski * so to be able to reuse it we need an extra ref.
823c10d12e3SJakub Kicinski */
824c10d12e3SJakub Kicinski if (skb && rxbuf && skb->head == rxbuf->frag)
825c10d12e3SJakub Kicinski page_ref_inc(virt_to_head_page(rxbuf->frag));
826c10d12e3SJakub Kicinski if (rxbuf)
827c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, rxbuf->frag, rxbuf->dma_addr);
828c10d12e3SJakub Kicinski if (skb)
829c10d12e3SJakub Kicinski dev_kfree_skb_any(skb);
830c10d12e3SJakub Kicinski }
831c10d12e3SJakub Kicinski
nfp_nfdk_xdp_complete(struct nfp_net_tx_ring * tx_ring)832d9d95049SYinjun Zhang static bool nfp_nfdk_xdp_complete(struct nfp_net_tx_ring *tx_ring)
833d9d95049SYinjun Zhang {
834d9d95049SYinjun Zhang struct nfp_net_r_vector *r_vec = tx_ring->r_vec;
835d9d95049SYinjun Zhang struct nfp_net_dp *dp = &r_vec->nfp_net->dp;
836d9d95049SYinjun Zhang struct nfp_net_rx_ring *rx_ring;
837d9d95049SYinjun Zhang u32 qcp_rd_p, done = 0;
838d9d95049SYinjun Zhang bool done_all;
839d9d95049SYinjun Zhang int todo;
840d9d95049SYinjun Zhang
841d9d95049SYinjun Zhang /* Work out how many descriptors have been transmitted */
842d9d95049SYinjun Zhang qcp_rd_p = nfp_net_read_tx_cmpl(tx_ring, dp);
843d9d95049SYinjun Zhang if (qcp_rd_p == tx_ring->qcp_rd_p)
844d9d95049SYinjun Zhang return true;
845d9d95049SYinjun Zhang
846d9d95049SYinjun Zhang todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p);
847d9d95049SYinjun Zhang
848d9d95049SYinjun Zhang done_all = todo <= NFP_NET_XDP_MAX_COMPLETE;
849d9d95049SYinjun Zhang todo = min(todo, NFP_NET_XDP_MAX_COMPLETE);
850d9d95049SYinjun Zhang
851d9d95049SYinjun Zhang rx_ring = r_vec->rx_ring;
852d9d95049SYinjun Zhang while (todo > 0) {
853d9d95049SYinjun Zhang int idx = D_IDX(tx_ring, tx_ring->rd_p + done);
854d9d95049SYinjun Zhang struct nfp_nfdk_tx_buf *txbuf;
855d9d95049SYinjun Zhang unsigned int step = 1;
856d9d95049SYinjun Zhang
857d9d95049SYinjun Zhang txbuf = &tx_ring->ktxbufs[idx];
858d9d95049SYinjun Zhang if (!txbuf->raw)
859d9d95049SYinjun Zhang goto next;
860d9d95049SYinjun Zhang
861d9d95049SYinjun Zhang if (NFDK_TX_BUF_INFO(txbuf->val) != NFDK_TX_BUF_INFO_SOP) {
862d9d95049SYinjun Zhang WARN_ONCE(1, "Unexpected TX buffer in XDP TX ring\n");
863d9d95049SYinjun Zhang goto next;
864d9d95049SYinjun Zhang }
865d9d95049SYinjun Zhang
866d9d95049SYinjun Zhang /* Two successive txbufs are used to stash virtual and dma
867d9d95049SYinjun Zhang * address respectively, recycle and clean them here.
868d9d95049SYinjun Zhang */
869d9d95049SYinjun Zhang nfp_nfdk_rx_give_one(dp, rx_ring,
870d9d95049SYinjun Zhang (void *)NFDK_TX_BUF_PTR(txbuf[0].val),
871d9d95049SYinjun Zhang txbuf[1].dma_addr);
872d9d95049SYinjun Zhang txbuf[0].raw = 0;
873d9d95049SYinjun Zhang txbuf[1].raw = 0;
874d9d95049SYinjun Zhang step = 2;
875d9d95049SYinjun Zhang
876d9d95049SYinjun Zhang u64_stats_update_begin(&r_vec->tx_sync);
877d9d95049SYinjun Zhang /* Note: tx_bytes not accumulated. */
878d9d95049SYinjun Zhang r_vec->tx_pkts++;
879d9d95049SYinjun Zhang u64_stats_update_end(&r_vec->tx_sync);
880d9d95049SYinjun Zhang next:
881d9d95049SYinjun Zhang todo -= step;
882d9d95049SYinjun Zhang done += step;
883d9d95049SYinjun Zhang }
884d9d95049SYinjun Zhang
885d9d95049SYinjun Zhang tx_ring->qcp_rd_p = D_IDX(tx_ring, tx_ring->qcp_rd_p + done);
886d9d95049SYinjun Zhang tx_ring->rd_p += done;
887d9d95049SYinjun Zhang
888d9d95049SYinjun Zhang WARN_ONCE(tx_ring->wr_p - tx_ring->rd_p > tx_ring->cnt,
889d9d95049SYinjun Zhang "XDP TX ring corruption rd_p=%u wr_p=%u cnt=%u\n",
890d9d95049SYinjun Zhang tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt);
891d9d95049SYinjun Zhang
892d9d95049SYinjun Zhang return done_all;
893d9d95049SYinjun Zhang }
894d9d95049SYinjun Zhang
895d9d95049SYinjun Zhang static bool
nfp_nfdk_tx_xdp_buf(struct nfp_net_dp * dp,struct nfp_net_rx_ring * rx_ring,struct nfp_net_tx_ring * tx_ring,struct nfp_net_rx_buf * rxbuf,unsigned int dma_off,unsigned int pkt_len,bool * completed)896d9d95049SYinjun Zhang nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
897d9d95049SYinjun Zhang struct nfp_net_tx_ring *tx_ring,
898d9d95049SYinjun Zhang struct nfp_net_rx_buf *rxbuf, unsigned int dma_off,
899d9d95049SYinjun Zhang unsigned int pkt_len, bool *completed)
900d9d95049SYinjun Zhang {
901d9d95049SYinjun Zhang unsigned int dma_map_sz = dp->fl_bufsz - NFP_NET_RX_BUF_NON_DATA;
902d9d95049SYinjun Zhang unsigned int dma_len, type, cnt, dlen_type, tmp_dlen;
903d9d95049SYinjun Zhang struct nfp_nfdk_tx_buf *txbuf;
904d9d95049SYinjun Zhang struct nfp_nfdk_tx_desc *txd;
905d9d95049SYinjun Zhang unsigned int n_descs;
906d9d95049SYinjun Zhang dma_addr_t dma_addr;
907d9d95049SYinjun Zhang int wr_idx;
908d9d95049SYinjun Zhang
909d9d95049SYinjun Zhang /* Reject if xdp_adjust_tail grow packet beyond DMA area */
910d9d95049SYinjun Zhang if (pkt_len + dma_off > dma_map_sz)
911d9d95049SYinjun Zhang return false;
912d9d95049SYinjun Zhang
913d9d95049SYinjun Zhang /* Make sure there's still at least one block available after
914d9d95049SYinjun Zhang * aligning to block boundary, so that the txds used below
915d9d95049SYinjun Zhang * won't wrap around the tx_ring.
916d9d95049SYinjun Zhang */
917d9d95049SYinjun Zhang if (unlikely(nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT))) {
918d9d95049SYinjun Zhang if (!*completed) {
919d9d95049SYinjun Zhang nfp_nfdk_xdp_complete(tx_ring);
920d9d95049SYinjun Zhang *completed = true;
921d9d95049SYinjun Zhang }
922d9d95049SYinjun Zhang
923d9d95049SYinjun Zhang if (unlikely(nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT))) {
924d9d95049SYinjun Zhang nfp_nfdk_rx_drop(dp, rx_ring->r_vec, rx_ring, rxbuf,
925d9d95049SYinjun Zhang NULL);
926d9d95049SYinjun Zhang return false;
927d9d95049SYinjun Zhang }
928d9d95049SYinjun Zhang }
929d9d95049SYinjun Zhang
930d9d95049SYinjun Zhang /* Check if cross block boundary */
931d9d95049SYinjun Zhang n_descs = nfp_nfdk_headlen_to_segs(pkt_len);
932d9d95049SYinjun Zhang if ((round_down(tx_ring->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
933d9d95049SYinjun Zhang round_down(tx_ring->wr_p + n_descs, NFDK_TX_DESC_BLOCK_CNT)) ||
934d9d95049SYinjun Zhang ((u32)tx_ring->data_pending + pkt_len >
935d9d95049SYinjun Zhang NFDK_TX_MAX_DATA_PER_BLOCK)) {
936d9d95049SYinjun Zhang unsigned int nop_slots = D_BLOCK_CPL(tx_ring->wr_p);
937d9d95049SYinjun Zhang
938d9d95049SYinjun Zhang wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
939d9d95049SYinjun Zhang txd = &tx_ring->ktxds[wr_idx];
940d9d95049SYinjun Zhang memset(txd, 0,
941d9d95049SYinjun Zhang array_size(nop_slots, sizeof(struct nfp_nfdk_tx_desc)));
942d9d95049SYinjun Zhang
943d9d95049SYinjun Zhang tx_ring->data_pending = 0;
944d9d95049SYinjun Zhang tx_ring->wr_p += nop_slots;
945d9d95049SYinjun Zhang tx_ring->wr_ptr_add += nop_slots;
946d9d95049SYinjun Zhang }
947d9d95049SYinjun Zhang
948d9d95049SYinjun Zhang wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
949d9d95049SYinjun Zhang
950d9d95049SYinjun Zhang txbuf = &tx_ring->ktxbufs[wr_idx];
951d9d95049SYinjun Zhang
952d9d95049SYinjun Zhang txbuf[0].val = (unsigned long)rxbuf->frag | NFDK_TX_BUF_INFO_SOP;
953d9d95049SYinjun Zhang txbuf[1].dma_addr = rxbuf->dma_addr;
954d9d95049SYinjun Zhang /* Note: pkt len not stored */
955d9d95049SYinjun Zhang
956d9d95049SYinjun Zhang dma_sync_single_for_device(dp->dev, rxbuf->dma_addr + dma_off,
957d9d95049SYinjun Zhang pkt_len, DMA_BIDIRECTIONAL);
958d9d95049SYinjun Zhang
959d9d95049SYinjun Zhang /* Build TX descriptor */
960d9d95049SYinjun Zhang txd = &tx_ring->ktxds[wr_idx];
961d9d95049SYinjun Zhang dma_len = pkt_len;
962d9d95049SYinjun Zhang dma_addr = rxbuf->dma_addr + dma_off;
963d9d95049SYinjun Zhang
9645c306de8SYinjun Zhang if (dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
965d9d95049SYinjun Zhang type = NFDK_DESC_TX_TYPE_SIMPLE;
966d9d95049SYinjun Zhang else
967d9d95049SYinjun Zhang type = NFDK_DESC_TX_TYPE_GATHER;
968d9d95049SYinjun Zhang
969d9d95049SYinjun Zhang /* FIELD_PREP() implicitly truncates to chunk */
970d9d95049SYinjun Zhang dma_len -= 1;
9719c840d5fSBaowen Zheng dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
9729c840d5fSBaowen Zheng dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
9739c840d5fSBaowen Zheng NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
974d9d95049SYinjun Zhang FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
975d9d95049SYinjun Zhang
976d9d95049SYinjun Zhang txd->dma_len_type = cpu_to_le16(dlen_type);
9775f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
978d9d95049SYinjun Zhang
979d9d95049SYinjun Zhang tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
980d9d95049SYinjun Zhang dma_len -= tmp_dlen;
981d9d95049SYinjun Zhang dma_addr += tmp_dlen + 1;
982d9d95049SYinjun Zhang txd++;
983d9d95049SYinjun Zhang
984d9d95049SYinjun Zhang while (dma_len > 0) {
985d9d95049SYinjun Zhang dma_len -= 1;
986d9d95049SYinjun Zhang dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
987d9d95049SYinjun Zhang txd->dma_len_type = cpu_to_le16(dlen_type);
9885f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
989d9d95049SYinjun Zhang
990d9d95049SYinjun Zhang dlen_type &= NFDK_DESC_TX_DMA_LEN;
991d9d95049SYinjun Zhang dma_len -= dlen_type;
992d9d95049SYinjun Zhang dma_addr += dlen_type + 1;
993d9d95049SYinjun Zhang txd++;
994d9d95049SYinjun Zhang }
995d9d95049SYinjun Zhang
996d9d95049SYinjun Zhang (txd - 1)->dma_len_type = cpu_to_le16(dlen_type | NFDK_DESC_TX_EOP);
997d9d95049SYinjun Zhang
998d9d95049SYinjun Zhang /* Metadata desc */
999d9d95049SYinjun Zhang txd->raw = 0;
1000d9d95049SYinjun Zhang txd++;
1001d9d95049SYinjun Zhang
1002d9d95049SYinjun Zhang cnt = txd - tx_ring->ktxds - wr_idx;
1003d9d95049SYinjun Zhang tx_ring->wr_p += cnt;
1004d9d95049SYinjun Zhang if (tx_ring->wr_p % NFDK_TX_DESC_BLOCK_CNT)
1005d9d95049SYinjun Zhang tx_ring->data_pending += pkt_len;
1006d9d95049SYinjun Zhang else
1007d9d95049SYinjun Zhang tx_ring->data_pending = 0;
1008d9d95049SYinjun Zhang
1009d9d95049SYinjun Zhang tx_ring->wr_ptr_add += cnt;
1010d9d95049SYinjun Zhang return true;
1011d9d95049SYinjun Zhang }
1012d9d95049SYinjun Zhang
1013c10d12e3SJakub Kicinski /**
1014c10d12e3SJakub Kicinski * nfp_nfdk_rx() - receive up to @budget packets on @rx_ring
1015c10d12e3SJakub Kicinski * @rx_ring: RX ring to receive from
1016c10d12e3SJakub Kicinski * @budget: NAPI budget
1017c10d12e3SJakub Kicinski *
1018c10d12e3SJakub Kicinski * Note, this function is separated out from the napi poll function to
1019c10d12e3SJakub Kicinski * more cleanly separate packet receive code from other bookkeeping
1020c10d12e3SJakub Kicinski * functions performed in the napi poll function.
1021c10d12e3SJakub Kicinski *
1022c10d12e3SJakub Kicinski * Return: Number of packets received.
1023c10d12e3SJakub Kicinski */
nfp_nfdk_rx(struct nfp_net_rx_ring * rx_ring,int budget)1024c10d12e3SJakub Kicinski static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget)
1025c10d12e3SJakub Kicinski {
1026c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec = rx_ring->r_vec;
1027c10d12e3SJakub Kicinski struct nfp_net_dp *dp = &r_vec->nfp_net->dp;
1028c10d12e3SJakub Kicinski struct nfp_net_tx_ring *tx_ring;
1029c10d12e3SJakub Kicinski struct bpf_prog *xdp_prog;
1030c10d12e3SJakub Kicinski bool xdp_tx_cmpl = false;
1031c10d12e3SJakub Kicinski unsigned int true_bufsz;
1032c10d12e3SJakub Kicinski struct sk_buff *skb;
1033c10d12e3SJakub Kicinski int pkts_polled = 0;
1034c10d12e3SJakub Kicinski struct xdp_buff xdp;
1035c10d12e3SJakub Kicinski int idx;
1036c10d12e3SJakub Kicinski
1037c10d12e3SJakub Kicinski xdp_prog = READ_ONCE(dp->xdp_prog);
1038c10d12e3SJakub Kicinski true_bufsz = xdp_prog ? PAGE_SIZE : dp->fl_bufsz;
1039c10d12e3SJakub Kicinski xdp_init_buff(&xdp, PAGE_SIZE - NFP_NET_RX_BUF_HEADROOM,
1040c10d12e3SJakub Kicinski &rx_ring->xdp_rxq);
1041c10d12e3SJakub Kicinski tx_ring = r_vec->xdp_ring;
1042c10d12e3SJakub Kicinski
1043c10d12e3SJakub Kicinski while (pkts_polled < budget) {
1044c10d12e3SJakub Kicinski unsigned int meta_len, data_len, meta_off, pkt_len, pkt_off;
1045c10d12e3SJakub Kicinski struct nfp_net_rx_buf *rxbuf;
1046c10d12e3SJakub Kicinski struct nfp_net_rx_desc *rxd;
1047c10d12e3SJakub Kicinski struct nfp_meta_parsed meta;
1048c10d12e3SJakub Kicinski bool redir_egress = false;
1049c10d12e3SJakub Kicinski struct net_device *netdev;
1050c10d12e3SJakub Kicinski dma_addr_t new_dma_addr;
1051c10d12e3SJakub Kicinski u32 meta_len_xdp = 0;
1052c10d12e3SJakub Kicinski void *new_frag;
1053c10d12e3SJakub Kicinski
1054c10d12e3SJakub Kicinski idx = D_IDX(rx_ring, rx_ring->rd_p);
1055c10d12e3SJakub Kicinski
1056c10d12e3SJakub Kicinski rxd = &rx_ring->rxds[idx];
1057c10d12e3SJakub Kicinski if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD))
1058c10d12e3SJakub Kicinski break;
1059c10d12e3SJakub Kicinski
1060c10d12e3SJakub Kicinski /* Memory barrier to ensure that we won't do other reads
1061c10d12e3SJakub Kicinski * before the DD bit.
1062c10d12e3SJakub Kicinski */
1063c10d12e3SJakub Kicinski dma_rmb();
1064c10d12e3SJakub Kicinski
1065c10d12e3SJakub Kicinski memset(&meta, 0, sizeof(meta));
1066c10d12e3SJakub Kicinski
1067c10d12e3SJakub Kicinski rx_ring->rd_p++;
1068c10d12e3SJakub Kicinski pkts_polled++;
1069c10d12e3SJakub Kicinski
1070c10d12e3SJakub Kicinski rxbuf = &rx_ring->rxbufs[idx];
1071c10d12e3SJakub Kicinski /* < meta_len >
1072c10d12e3SJakub Kicinski * <-- [rx_offset] -->
1073c10d12e3SJakub Kicinski * ---------------------------------------------------------
1074c10d12e3SJakub Kicinski * | [XX] | metadata | packet | XXXX |
1075c10d12e3SJakub Kicinski * ---------------------------------------------------------
1076c10d12e3SJakub Kicinski * <---------------- data_len --------------->
1077c10d12e3SJakub Kicinski *
1078c10d12e3SJakub Kicinski * The rx_offset is fixed for all packets, the meta_len can vary
1079c10d12e3SJakub Kicinski * on a packet by packet basis. If rx_offset is set to zero
1080c10d12e3SJakub Kicinski * (_RX_OFFSET_DYNAMIC) metadata starts at the beginning of the
1081c10d12e3SJakub Kicinski * buffer and is immediately followed by the packet (no [XX]).
1082c10d12e3SJakub Kicinski */
1083c10d12e3SJakub Kicinski meta_len = rxd->rxd.meta_len_dd & PCIE_DESC_RX_META_LEN_MASK;
1084c10d12e3SJakub Kicinski data_len = le16_to_cpu(rxd->rxd.data_len);
1085c10d12e3SJakub Kicinski pkt_len = data_len - meta_len;
1086c10d12e3SJakub Kicinski
1087c10d12e3SJakub Kicinski pkt_off = NFP_NET_RX_BUF_HEADROOM + dp->rx_dma_off;
1088c10d12e3SJakub Kicinski if (dp->rx_offset == NFP_NET_CFG_RX_OFFSET_DYNAMIC)
1089c10d12e3SJakub Kicinski pkt_off += meta_len;
1090c10d12e3SJakub Kicinski else
1091c10d12e3SJakub Kicinski pkt_off += dp->rx_offset;
1092c10d12e3SJakub Kicinski meta_off = pkt_off - meta_len;
1093c10d12e3SJakub Kicinski
1094c10d12e3SJakub Kicinski /* Stats update */
1095c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
1096c10d12e3SJakub Kicinski r_vec->rx_pkts++;
1097c10d12e3SJakub Kicinski r_vec->rx_bytes += pkt_len;
1098c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
1099c10d12e3SJakub Kicinski
1100c10d12e3SJakub Kicinski if (unlikely(meta_len > NFP_NET_MAX_PREPEND ||
1101c10d12e3SJakub Kicinski (dp->rx_offset && meta_len > dp->rx_offset))) {
1102c10d12e3SJakub Kicinski nn_dp_warn(dp, "oversized RX packet metadata %u\n",
1103c10d12e3SJakub Kicinski meta_len);
1104c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL);
1105c10d12e3SJakub Kicinski continue;
1106c10d12e3SJakub Kicinski }
1107c10d12e3SJakub Kicinski
1108c10d12e3SJakub Kicinski nfp_net_dma_sync_cpu_rx(dp, rxbuf->dma_addr + meta_off,
1109c10d12e3SJakub Kicinski data_len);
1110c10d12e3SJakub Kicinski
1111c10d12e3SJakub Kicinski if (meta_len) {
1112c10d12e3SJakub Kicinski if (unlikely(nfp_nfdk_parse_meta(dp->netdev, &meta,
1113c10d12e3SJakub Kicinski rxbuf->frag + meta_off,
1114c10d12e3SJakub Kicinski rxbuf->frag + pkt_off,
1115c10d12e3SJakub Kicinski pkt_len, meta_len))) {
1116c10d12e3SJakub Kicinski nn_dp_warn(dp, "invalid RX packet metadata\n");
1117c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf,
1118c10d12e3SJakub Kicinski NULL);
1119c10d12e3SJakub Kicinski continue;
1120c10d12e3SJakub Kicinski }
1121c10d12e3SJakub Kicinski }
1122c10d12e3SJakub Kicinski
1123c10d12e3SJakub Kicinski if (xdp_prog && !meta.portid) {
1124c10d12e3SJakub Kicinski void *orig_data = rxbuf->frag + pkt_off;
1125d9d95049SYinjun Zhang unsigned int dma_off;
1126c10d12e3SJakub Kicinski int act;
1127c10d12e3SJakub Kicinski
1128c10d12e3SJakub Kicinski xdp_prepare_buff(&xdp,
1129c10d12e3SJakub Kicinski rxbuf->frag + NFP_NET_RX_BUF_HEADROOM,
1130c10d12e3SJakub Kicinski pkt_off - NFP_NET_RX_BUF_HEADROOM,
1131c10d12e3SJakub Kicinski pkt_len, true);
1132c10d12e3SJakub Kicinski
1133c10d12e3SJakub Kicinski act = bpf_prog_run_xdp(xdp_prog, &xdp);
1134c10d12e3SJakub Kicinski
1135c10d12e3SJakub Kicinski pkt_len = xdp.data_end - xdp.data;
1136c10d12e3SJakub Kicinski pkt_off += xdp.data - orig_data;
1137c10d12e3SJakub Kicinski
1138c10d12e3SJakub Kicinski switch (act) {
1139c10d12e3SJakub Kicinski case XDP_PASS:
1140c10d12e3SJakub Kicinski meta_len_xdp = xdp.data - xdp.data_meta;
1141c10d12e3SJakub Kicinski break;
1142d9d95049SYinjun Zhang case XDP_TX:
1143d9d95049SYinjun Zhang dma_off = pkt_off - NFP_NET_RX_BUF_HEADROOM;
1144d9d95049SYinjun Zhang if (unlikely(!nfp_nfdk_tx_xdp_buf(dp, rx_ring,
1145d9d95049SYinjun Zhang tx_ring,
1146d9d95049SYinjun Zhang rxbuf,
1147d9d95049SYinjun Zhang dma_off,
1148d9d95049SYinjun Zhang pkt_len,
1149d9d95049SYinjun Zhang &xdp_tx_cmpl)))
1150d9d95049SYinjun Zhang trace_xdp_exception(dp->netdev,
1151d9d95049SYinjun Zhang xdp_prog, act);
1152d9d95049SYinjun Zhang continue;
1153c10d12e3SJakub Kicinski default:
1154c10d12e3SJakub Kicinski bpf_warn_invalid_xdp_action(dp->netdev, xdp_prog, act);
1155c10d12e3SJakub Kicinski fallthrough;
1156c10d12e3SJakub Kicinski case XDP_ABORTED:
1157c10d12e3SJakub Kicinski trace_xdp_exception(dp->netdev, xdp_prog, act);
1158c10d12e3SJakub Kicinski fallthrough;
1159c10d12e3SJakub Kicinski case XDP_DROP:
1160c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, rxbuf->frag,
1161c10d12e3SJakub Kicinski rxbuf->dma_addr);
1162c10d12e3SJakub Kicinski continue;
1163c10d12e3SJakub Kicinski }
1164c10d12e3SJakub Kicinski }
1165c10d12e3SJakub Kicinski
1166c10d12e3SJakub Kicinski if (likely(!meta.portid)) {
1167c10d12e3SJakub Kicinski netdev = dp->netdev;
1168c10d12e3SJakub Kicinski } else if (meta.portid == NFP_META_PORT_ID_CTRL) {
1169c10d12e3SJakub Kicinski struct nfp_net *nn = netdev_priv(dp->netdev);
1170c10d12e3SJakub Kicinski
1171c10d12e3SJakub Kicinski nfp_app_ctrl_rx_raw(nn->app, rxbuf->frag + pkt_off,
1172c10d12e3SJakub Kicinski pkt_len);
1173c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, rxbuf->frag,
1174c10d12e3SJakub Kicinski rxbuf->dma_addr);
1175c10d12e3SJakub Kicinski continue;
1176c10d12e3SJakub Kicinski } else {
1177c10d12e3SJakub Kicinski struct nfp_net *nn;
1178c10d12e3SJakub Kicinski
1179c10d12e3SJakub Kicinski nn = netdev_priv(dp->netdev);
1180c10d12e3SJakub Kicinski netdev = nfp_app_dev_get(nn->app, meta.portid,
1181c10d12e3SJakub Kicinski &redir_egress);
1182c10d12e3SJakub Kicinski if (unlikely(!netdev)) {
1183c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf,
1184c10d12e3SJakub Kicinski NULL);
1185c10d12e3SJakub Kicinski continue;
1186c10d12e3SJakub Kicinski }
1187c10d12e3SJakub Kicinski
1188c10d12e3SJakub Kicinski if (nfp_netdev_is_nfp_repr(netdev))
1189c10d12e3SJakub Kicinski nfp_repr_inc_rx_stats(netdev, pkt_len);
1190c10d12e3SJakub Kicinski }
1191c10d12e3SJakub Kicinski
1192c10d12e3SJakub Kicinski skb = build_skb(rxbuf->frag, true_bufsz);
1193c10d12e3SJakub Kicinski if (unlikely(!skb)) {
1194c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL);
1195c10d12e3SJakub Kicinski continue;
1196c10d12e3SJakub Kicinski }
1197c10d12e3SJakub Kicinski new_frag = nfp_nfdk_napi_alloc_one(dp, &new_dma_addr);
1198c10d12e3SJakub Kicinski if (unlikely(!new_frag)) {
1199c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, skb);
1200c10d12e3SJakub Kicinski continue;
1201c10d12e3SJakub Kicinski }
1202c10d12e3SJakub Kicinski
1203c10d12e3SJakub Kicinski nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr);
1204c10d12e3SJakub Kicinski
1205c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);
1206c10d12e3SJakub Kicinski
1207c10d12e3SJakub Kicinski skb_reserve(skb, pkt_off);
1208c10d12e3SJakub Kicinski skb_put(skb, pkt_len);
1209c10d12e3SJakub Kicinski
1210c10d12e3SJakub Kicinski skb->mark = meta.mark;
1211c10d12e3SJakub Kicinski skb_set_hash(skb, meta.hash, meta.hash_type);
1212c10d12e3SJakub Kicinski
1213c10d12e3SJakub Kicinski skb_record_rx_queue(skb, rx_ring->idx);
1214c10d12e3SJakub Kicinski skb->protocol = eth_type_trans(skb, netdev);
1215c10d12e3SJakub Kicinski
1216c10d12e3SJakub Kicinski nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb);
1217c10d12e3SJakub Kicinski
121867d2656bSDiana Wang if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
121967d2656bSDiana Wang nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
122067d2656bSDiana Wang continue;
122167d2656bSDiana Wang }
122267d2656bSDiana Wang
1223436396f2SHuanhuan Wang #ifdef CONFIG_NFP_NET_IPSEC
1224436396f2SHuanhuan Wang if (meta.ipsec_saidx != 0 && unlikely(nfp_net_ipsec_rx(&meta, skb))) {
1225436396f2SHuanhuan Wang nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
1226436396f2SHuanhuan Wang continue;
1227436396f2SHuanhuan Wang }
1228436396f2SHuanhuan Wang #endif
1229436396f2SHuanhuan Wang
1230c10d12e3SJakub Kicinski if (meta_len_xdp)
1231c10d12e3SJakub Kicinski skb_metadata_set(skb, meta_len_xdp);
1232c10d12e3SJakub Kicinski
1233c10d12e3SJakub Kicinski if (likely(!redir_egress)) {
1234c10d12e3SJakub Kicinski napi_gro_receive(&rx_ring->r_vec->napi, skb);
1235c10d12e3SJakub Kicinski } else {
1236c10d12e3SJakub Kicinski skb->dev = netdev;
1237c10d12e3SJakub Kicinski skb_reset_network_header(skb);
1238c10d12e3SJakub Kicinski __skb_push(skb, ETH_HLEN);
1239c10d12e3SJakub Kicinski dev_queue_xmit(skb);
1240c10d12e3SJakub Kicinski }
1241c10d12e3SJakub Kicinski }
1242c10d12e3SJakub Kicinski
1243c10d12e3SJakub Kicinski if (xdp_prog) {
1244c10d12e3SJakub Kicinski if (tx_ring->wr_ptr_add)
1245c10d12e3SJakub Kicinski nfp_net_tx_xmit_more_flush(tx_ring);
1246c10d12e3SJakub Kicinski else if (unlikely(tx_ring->wr_p != tx_ring->rd_p) &&
1247c10d12e3SJakub Kicinski !xdp_tx_cmpl)
1248c10d12e3SJakub Kicinski if (!nfp_nfdk_xdp_complete(tx_ring))
1249c10d12e3SJakub Kicinski pkts_polled = budget;
1250c10d12e3SJakub Kicinski }
1251c10d12e3SJakub Kicinski
1252c10d12e3SJakub Kicinski return pkts_polled;
1253c10d12e3SJakub Kicinski }
1254c10d12e3SJakub Kicinski
1255c10d12e3SJakub Kicinski /**
1256c10d12e3SJakub Kicinski * nfp_nfdk_poll() - napi poll function
1257c10d12e3SJakub Kicinski * @napi: NAPI structure
1258c10d12e3SJakub Kicinski * @budget: NAPI budget
1259c10d12e3SJakub Kicinski *
1260c10d12e3SJakub Kicinski * Return: number of packets polled.
1261c10d12e3SJakub Kicinski */
nfp_nfdk_poll(struct napi_struct * napi,int budget)1262c10d12e3SJakub Kicinski int nfp_nfdk_poll(struct napi_struct *napi, int budget)
1263c10d12e3SJakub Kicinski {
1264c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec =
1265c10d12e3SJakub Kicinski container_of(napi, struct nfp_net_r_vector, napi);
1266c10d12e3SJakub Kicinski unsigned int pkts_polled = 0;
1267c10d12e3SJakub Kicinski
1268c10d12e3SJakub Kicinski if (r_vec->tx_ring)
1269c10d12e3SJakub Kicinski nfp_nfdk_tx_complete(r_vec->tx_ring, budget);
1270c10d12e3SJakub Kicinski if (r_vec->rx_ring)
1271c10d12e3SJakub Kicinski pkts_polled = nfp_nfdk_rx(r_vec->rx_ring, budget);
1272c10d12e3SJakub Kicinski
1273c10d12e3SJakub Kicinski if (pkts_polled < budget)
1274c10d12e3SJakub Kicinski if (napi_complete_done(napi, pkts_polled))
1275c10d12e3SJakub Kicinski nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
1276c10d12e3SJakub Kicinski
1277c10d12e3SJakub Kicinski if (r_vec->nfp_net->rx_coalesce_adapt_on && r_vec->rx_ring) {
1278c10d12e3SJakub Kicinski struct dim_sample dim_sample = {};
1279c10d12e3SJakub Kicinski unsigned int start;
1280c10d12e3SJakub Kicinski u64 pkts, bytes;
1281c10d12e3SJakub Kicinski
1282c10d12e3SJakub Kicinski do {
1283c10d12e3SJakub Kicinski start = u64_stats_fetch_begin(&r_vec->rx_sync);
1284c10d12e3SJakub Kicinski pkts = r_vec->rx_pkts;
1285c10d12e3SJakub Kicinski bytes = r_vec->rx_bytes;
1286c10d12e3SJakub Kicinski } while (u64_stats_fetch_retry(&r_vec->rx_sync, start));
1287c10d12e3SJakub Kicinski
1288c10d12e3SJakub Kicinski dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
1289c10d12e3SJakub Kicinski net_dim(&r_vec->rx_dim, dim_sample);
1290c10d12e3SJakub Kicinski }
1291c10d12e3SJakub Kicinski
1292c10d12e3SJakub Kicinski if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) {
1293c10d12e3SJakub Kicinski struct dim_sample dim_sample = {};
1294c10d12e3SJakub Kicinski unsigned int start;
1295c10d12e3SJakub Kicinski u64 pkts, bytes;
1296c10d12e3SJakub Kicinski
1297c10d12e3SJakub Kicinski do {
1298c10d12e3SJakub Kicinski start = u64_stats_fetch_begin(&r_vec->tx_sync);
1299c10d12e3SJakub Kicinski pkts = r_vec->tx_pkts;
1300c10d12e3SJakub Kicinski bytes = r_vec->tx_bytes;
1301c10d12e3SJakub Kicinski } while (u64_stats_fetch_retry(&r_vec->tx_sync, start));
1302c10d12e3SJakub Kicinski
1303c10d12e3SJakub Kicinski dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
1304c10d12e3SJakub Kicinski net_dim(&r_vec->tx_dim, dim_sample);
1305c10d12e3SJakub Kicinski }
1306c10d12e3SJakub Kicinski
1307c10d12e3SJakub Kicinski return pkts_polled;
1308c10d12e3SJakub Kicinski }
1309c10d12e3SJakub Kicinski
1310c10d12e3SJakub Kicinski /* Control device data path
1311c10d12e3SJakub Kicinski */
1312c10d12e3SJakub Kicinski
1313c10d12e3SJakub Kicinski bool
nfp_nfdk_ctrl_tx_one(struct nfp_net * nn,struct nfp_net_r_vector * r_vec,struct sk_buff * skb,bool old)1314c10d12e3SJakub Kicinski nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
1315c10d12e3SJakub Kicinski struct sk_buff *skb, bool old)
1316c10d12e3SJakub Kicinski {
1317c10d12e3SJakub Kicinski u32 cnt, tmp_dlen, dlen_type = 0;
1318c10d12e3SJakub Kicinski struct nfp_net_tx_ring *tx_ring;
1319c10d12e3SJakub Kicinski struct nfp_nfdk_tx_buf *txbuf;
1320c10d12e3SJakub Kicinski struct nfp_nfdk_tx_desc *txd;
1321c10d12e3SJakub Kicinski unsigned int dma_len, type;
1322c10d12e3SJakub Kicinski struct nfp_net_dp *dp;
1323c10d12e3SJakub Kicinski dma_addr_t dma_addr;
1324c10d12e3SJakub Kicinski u64 metadata = 0;
1325c10d12e3SJakub Kicinski int wr_idx;
1326c10d12e3SJakub Kicinski
1327c10d12e3SJakub Kicinski dp = &r_vec->nfp_net->dp;
1328c10d12e3SJakub Kicinski tx_ring = r_vec->tx_ring;
1329c10d12e3SJakub Kicinski
1330c10d12e3SJakub Kicinski if (WARN_ON_ONCE(skb_shinfo(skb)->nr_frags)) {
1331c10d12e3SJakub Kicinski nn_dp_warn(dp, "Driver's CTRL TX does not implement gather\n");
1332c10d12e3SJakub Kicinski goto err_free;
1333c10d12e3SJakub Kicinski }
1334c10d12e3SJakub Kicinski
1335c10d12e3SJakub Kicinski /* Don't bother counting frags, assume the worst */
1336c10d12e3SJakub Kicinski if (unlikely(nfp_net_tx_full(tx_ring, NFDK_TX_DESC_STOP_CNT))) {
1337c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
1338c10d12e3SJakub Kicinski r_vec->tx_busy++;
1339c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
1340c10d12e3SJakub Kicinski if (!old)
1341c10d12e3SJakub Kicinski __skb_queue_tail(&r_vec->queue, skb);
1342c10d12e3SJakub Kicinski else
1343c10d12e3SJakub Kicinski __skb_queue_head(&r_vec->queue, skb);
1344c10d12e3SJakub Kicinski return NETDEV_TX_BUSY;
1345c10d12e3SJakub Kicinski }
1346c10d12e3SJakub Kicinski
1347c10d12e3SJakub Kicinski if (nfp_app_ctrl_has_meta(nn->app)) {
1348c10d12e3SJakub Kicinski if (unlikely(skb_headroom(skb) < 8)) {
1349c10d12e3SJakub Kicinski nn_dp_warn(dp, "CTRL TX on skb without headroom\n");
1350c10d12e3SJakub Kicinski goto err_free;
1351c10d12e3SJakub Kicinski }
1352c10d12e3SJakub Kicinski metadata = NFDK_DESC_TX_CHAIN_META;
1353c10d12e3SJakub Kicinski put_unaligned_be32(NFP_META_PORT_ID_CTRL, skb_push(skb, 4));
1354c10d12e3SJakub Kicinski put_unaligned_be32(FIELD_PREP(NFDK_META_LEN, 8) |
1355c10d12e3SJakub Kicinski FIELD_PREP(NFDK_META_FIELDS,
1356c10d12e3SJakub Kicinski NFP_NET_META_PORTID),
1357c10d12e3SJakub Kicinski skb_push(skb, 4));
1358c10d12e3SJakub Kicinski }
1359c10d12e3SJakub Kicinski
13609c840d5fSBaowen Zheng if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
1361c10d12e3SJakub Kicinski goto err_free;
1362c10d12e3SJakub Kicinski
1363c10d12e3SJakub Kicinski /* DMA map all */
1364c10d12e3SJakub Kicinski wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
1365c10d12e3SJakub Kicinski txd = &tx_ring->ktxds[wr_idx];
1366c10d12e3SJakub Kicinski txbuf = &tx_ring->ktxbufs[wr_idx];
1367c10d12e3SJakub Kicinski
1368c10d12e3SJakub Kicinski dma_len = skb_headlen(skb);
13695c306de8SYinjun Zhang if (dma_len <= NFDK_TX_MAX_DATA_PER_HEAD)
1370c10d12e3SJakub Kicinski type = NFDK_DESC_TX_TYPE_SIMPLE;
1371c10d12e3SJakub Kicinski else
1372c10d12e3SJakub Kicinski type = NFDK_DESC_TX_TYPE_GATHER;
1373c10d12e3SJakub Kicinski
1374c10d12e3SJakub Kicinski dma_addr = dma_map_single(dp->dev, skb->data, dma_len, DMA_TO_DEVICE);
1375c10d12e3SJakub Kicinski if (dma_mapping_error(dp->dev, dma_addr))
1376c10d12e3SJakub Kicinski goto err_warn_dma;
1377c10d12e3SJakub Kicinski
1378c10d12e3SJakub Kicinski txbuf->skb = skb;
1379c10d12e3SJakub Kicinski txbuf++;
1380c10d12e3SJakub Kicinski
1381c10d12e3SJakub Kicinski txbuf->dma_addr = dma_addr;
1382c10d12e3SJakub Kicinski txbuf++;
1383c10d12e3SJakub Kicinski
1384c10d12e3SJakub Kicinski dma_len -= 1;
13859c840d5fSBaowen Zheng dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
13869c840d5fSBaowen Zheng dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
13879c840d5fSBaowen Zheng NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
1388c10d12e3SJakub Kicinski FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
1389c10d12e3SJakub Kicinski
1390c10d12e3SJakub Kicinski txd->dma_len_type = cpu_to_le16(dlen_type);
13915f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
1392c10d12e3SJakub Kicinski
1393c10d12e3SJakub Kicinski tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
1394c10d12e3SJakub Kicinski dma_len -= tmp_dlen;
1395c10d12e3SJakub Kicinski dma_addr += tmp_dlen + 1;
1396c10d12e3SJakub Kicinski txd++;
1397c10d12e3SJakub Kicinski
1398c10d12e3SJakub Kicinski while (dma_len > 0) {
1399c10d12e3SJakub Kicinski dma_len -= 1;
1400c10d12e3SJakub Kicinski dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
1401c10d12e3SJakub Kicinski txd->dma_len_type = cpu_to_le16(dlen_type);
14025f30671dSYinjun Zhang nfp_desc_set_dma_addr_48b(txd, dma_addr);
1403c10d12e3SJakub Kicinski
1404c10d12e3SJakub Kicinski dlen_type &= NFDK_DESC_TX_DMA_LEN;
1405c10d12e3SJakub Kicinski dma_len -= dlen_type;
1406c10d12e3SJakub Kicinski dma_addr += dlen_type + 1;
1407c10d12e3SJakub Kicinski txd++;
1408c10d12e3SJakub Kicinski }
1409c10d12e3SJakub Kicinski
1410c10d12e3SJakub Kicinski (txd - 1)->dma_len_type = cpu_to_le16(dlen_type | NFDK_DESC_TX_EOP);
1411c10d12e3SJakub Kicinski
1412c10d12e3SJakub Kicinski /* Metadata desc */
1413c10d12e3SJakub Kicinski txd->raw = cpu_to_le64(metadata);
1414c10d12e3SJakub Kicinski txd++;
1415c10d12e3SJakub Kicinski
1416c10d12e3SJakub Kicinski cnt = txd - tx_ring->ktxds - wr_idx;
1417c10d12e3SJakub Kicinski if (unlikely(round_down(wr_idx, NFDK_TX_DESC_BLOCK_CNT) !=
1418c10d12e3SJakub Kicinski round_down(wr_idx + cnt - 1, NFDK_TX_DESC_BLOCK_CNT)))
1419c10d12e3SJakub Kicinski goto err_warn_overflow;
1420c10d12e3SJakub Kicinski
1421c10d12e3SJakub Kicinski tx_ring->wr_p += cnt;
1422c10d12e3SJakub Kicinski if (tx_ring->wr_p % NFDK_TX_DESC_BLOCK_CNT)
1423c10d12e3SJakub Kicinski tx_ring->data_pending += skb->len;
1424c10d12e3SJakub Kicinski else
1425c10d12e3SJakub Kicinski tx_ring->data_pending = 0;
1426c10d12e3SJakub Kicinski
1427c10d12e3SJakub Kicinski tx_ring->wr_ptr_add += cnt;
1428c10d12e3SJakub Kicinski nfp_net_tx_xmit_more_flush(tx_ring);
1429c10d12e3SJakub Kicinski
1430c10d12e3SJakub Kicinski return NETDEV_TX_OK;
1431c10d12e3SJakub Kicinski
1432c10d12e3SJakub Kicinski err_warn_overflow:
1433c10d12e3SJakub Kicinski WARN_ONCE(1, "unable to fit packet into a descriptor wr_idx:%d head:%d frags:%d cnt:%d",
1434c10d12e3SJakub Kicinski wr_idx, skb_headlen(skb), 0, cnt);
1435c10d12e3SJakub Kicinski txbuf--;
1436c10d12e3SJakub Kicinski dma_unmap_single(dp->dev, txbuf->dma_addr,
1437c10d12e3SJakub Kicinski skb_headlen(skb), DMA_TO_DEVICE);
1438c10d12e3SJakub Kicinski txbuf->raw = 0;
1439c10d12e3SJakub Kicinski err_warn_dma:
1440c10d12e3SJakub Kicinski nn_dp_warn(dp, "Failed to map DMA TX buffer\n");
1441c10d12e3SJakub Kicinski err_free:
1442c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->tx_sync);
1443c10d12e3SJakub Kicinski r_vec->tx_errors++;
1444c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->tx_sync);
1445c10d12e3SJakub Kicinski dev_kfree_skb_any(skb);
1446c10d12e3SJakub Kicinski return NETDEV_TX_OK;
1447c10d12e3SJakub Kicinski }
1448c10d12e3SJakub Kicinski
__nfp_ctrl_tx_queued(struct nfp_net_r_vector * r_vec)1449c10d12e3SJakub Kicinski static void __nfp_ctrl_tx_queued(struct nfp_net_r_vector *r_vec)
1450c10d12e3SJakub Kicinski {
1451c10d12e3SJakub Kicinski struct sk_buff *skb;
1452c10d12e3SJakub Kicinski
1453c10d12e3SJakub Kicinski while ((skb = __skb_dequeue(&r_vec->queue)))
1454c10d12e3SJakub Kicinski if (nfp_nfdk_ctrl_tx_one(r_vec->nfp_net, r_vec, skb, true))
1455c10d12e3SJakub Kicinski return;
1456c10d12e3SJakub Kicinski }
1457c10d12e3SJakub Kicinski
1458c10d12e3SJakub Kicinski static bool
nfp_ctrl_meta_ok(struct nfp_net * nn,void * data,unsigned int meta_len)1459c10d12e3SJakub Kicinski nfp_ctrl_meta_ok(struct nfp_net *nn, void *data, unsigned int meta_len)
1460c10d12e3SJakub Kicinski {
1461c10d12e3SJakub Kicinski u32 meta_type, meta_tag;
1462c10d12e3SJakub Kicinski
1463c10d12e3SJakub Kicinski if (!nfp_app_ctrl_has_meta(nn->app))
1464c10d12e3SJakub Kicinski return !meta_len;
1465c10d12e3SJakub Kicinski
1466c10d12e3SJakub Kicinski if (meta_len != 8)
1467c10d12e3SJakub Kicinski return false;
1468c10d12e3SJakub Kicinski
1469c10d12e3SJakub Kicinski meta_type = get_unaligned_be32(data);
1470c10d12e3SJakub Kicinski meta_tag = get_unaligned_be32(data + 4);
1471c10d12e3SJakub Kicinski
1472c10d12e3SJakub Kicinski return (meta_type == NFP_NET_META_PORTID &&
1473c10d12e3SJakub Kicinski meta_tag == NFP_META_PORT_ID_CTRL);
1474c10d12e3SJakub Kicinski }
1475c10d12e3SJakub Kicinski
1476c10d12e3SJakub Kicinski static bool
nfp_ctrl_rx_one(struct nfp_net * nn,struct nfp_net_dp * dp,struct nfp_net_r_vector * r_vec,struct nfp_net_rx_ring * rx_ring)1477c10d12e3SJakub Kicinski nfp_ctrl_rx_one(struct nfp_net *nn, struct nfp_net_dp *dp,
1478c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec, struct nfp_net_rx_ring *rx_ring)
1479c10d12e3SJakub Kicinski {
1480c10d12e3SJakub Kicinski unsigned int meta_len, data_len, meta_off, pkt_len, pkt_off;
1481c10d12e3SJakub Kicinski struct nfp_net_rx_buf *rxbuf;
1482c10d12e3SJakub Kicinski struct nfp_net_rx_desc *rxd;
1483c10d12e3SJakub Kicinski dma_addr_t new_dma_addr;
1484c10d12e3SJakub Kicinski struct sk_buff *skb;
1485c10d12e3SJakub Kicinski void *new_frag;
1486c10d12e3SJakub Kicinski int idx;
1487c10d12e3SJakub Kicinski
1488c10d12e3SJakub Kicinski idx = D_IDX(rx_ring, rx_ring->rd_p);
1489c10d12e3SJakub Kicinski
1490c10d12e3SJakub Kicinski rxd = &rx_ring->rxds[idx];
1491c10d12e3SJakub Kicinski if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD))
1492c10d12e3SJakub Kicinski return false;
1493c10d12e3SJakub Kicinski
1494c10d12e3SJakub Kicinski /* Memory barrier to ensure that we won't do other reads
1495c10d12e3SJakub Kicinski * before the DD bit.
1496c10d12e3SJakub Kicinski */
1497c10d12e3SJakub Kicinski dma_rmb();
1498c10d12e3SJakub Kicinski
1499c10d12e3SJakub Kicinski rx_ring->rd_p++;
1500c10d12e3SJakub Kicinski
1501c10d12e3SJakub Kicinski rxbuf = &rx_ring->rxbufs[idx];
1502c10d12e3SJakub Kicinski meta_len = rxd->rxd.meta_len_dd & PCIE_DESC_RX_META_LEN_MASK;
1503c10d12e3SJakub Kicinski data_len = le16_to_cpu(rxd->rxd.data_len);
1504c10d12e3SJakub Kicinski pkt_len = data_len - meta_len;
1505c10d12e3SJakub Kicinski
1506c10d12e3SJakub Kicinski pkt_off = NFP_NET_RX_BUF_HEADROOM + dp->rx_dma_off;
1507c10d12e3SJakub Kicinski if (dp->rx_offset == NFP_NET_CFG_RX_OFFSET_DYNAMIC)
1508c10d12e3SJakub Kicinski pkt_off += meta_len;
1509c10d12e3SJakub Kicinski else
1510c10d12e3SJakub Kicinski pkt_off += dp->rx_offset;
1511c10d12e3SJakub Kicinski meta_off = pkt_off - meta_len;
1512c10d12e3SJakub Kicinski
1513c10d12e3SJakub Kicinski /* Stats update */
1514c10d12e3SJakub Kicinski u64_stats_update_begin(&r_vec->rx_sync);
1515c10d12e3SJakub Kicinski r_vec->rx_pkts++;
1516c10d12e3SJakub Kicinski r_vec->rx_bytes += pkt_len;
1517c10d12e3SJakub Kicinski u64_stats_update_end(&r_vec->rx_sync);
1518c10d12e3SJakub Kicinski
1519c10d12e3SJakub Kicinski nfp_net_dma_sync_cpu_rx(dp, rxbuf->dma_addr + meta_off, data_len);
1520c10d12e3SJakub Kicinski
1521c10d12e3SJakub Kicinski if (unlikely(!nfp_ctrl_meta_ok(nn, rxbuf->frag + meta_off, meta_len))) {
1522c10d12e3SJakub Kicinski nn_dp_warn(dp, "incorrect metadata for ctrl packet (%d)\n",
1523c10d12e3SJakub Kicinski meta_len);
1524c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL);
1525c10d12e3SJakub Kicinski return true;
1526c10d12e3SJakub Kicinski }
1527c10d12e3SJakub Kicinski
1528c10d12e3SJakub Kicinski skb = build_skb(rxbuf->frag, dp->fl_bufsz);
1529c10d12e3SJakub Kicinski if (unlikely(!skb)) {
1530c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL);
1531c10d12e3SJakub Kicinski return true;
1532c10d12e3SJakub Kicinski }
1533c10d12e3SJakub Kicinski new_frag = nfp_nfdk_napi_alloc_one(dp, &new_dma_addr);
1534c10d12e3SJakub Kicinski if (unlikely(!new_frag)) {
1535c10d12e3SJakub Kicinski nfp_nfdk_rx_drop(dp, r_vec, rx_ring, rxbuf, skb);
1536c10d12e3SJakub Kicinski return true;
1537c10d12e3SJakub Kicinski }
1538c10d12e3SJakub Kicinski
1539c10d12e3SJakub Kicinski nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr);
1540c10d12e3SJakub Kicinski
1541c10d12e3SJakub Kicinski nfp_nfdk_rx_give_one(dp, rx_ring, new_frag, new_dma_addr);
1542c10d12e3SJakub Kicinski
1543c10d12e3SJakub Kicinski skb_reserve(skb, pkt_off);
1544c10d12e3SJakub Kicinski skb_put(skb, pkt_len);
1545c10d12e3SJakub Kicinski
1546c10d12e3SJakub Kicinski nfp_app_ctrl_rx(nn->app, skb);
1547c10d12e3SJakub Kicinski
1548c10d12e3SJakub Kicinski return true;
1549c10d12e3SJakub Kicinski }
1550c10d12e3SJakub Kicinski
nfp_ctrl_rx(struct nfp_net_r_vector * r_vec)1551c10d12e3SJakub Kicinski static bool nfp_ctrl_rx(struct nfp_net_r_vector *r_vec)
1552c10d12e3SJakub Kicinski {
1553c10d12e3SJakub Kicinski struct nfp_net_rx_ring *rx_ring = r_vec->rx_ring;
1554c10d12e3SJakub Kicinski struct nfp_net *nn = r_vec->nfp_net;
1555c10d12e3SJakub Kicinski struct nfp_net_dp *dp = &nn->dp;
1556c10d12e3SJakub Kicinski unsigned int budget = 512;
1557c10d12e3SJakub Kicinski
1558c10d12e3SJakub Kicinski while (nfp_ctrl_rx_one(nn, dp, r_vec, rx_ring) && budget--)
1559c10d12e3SJakub Kicinski continue;
1560c10d12e3SJakub Kicinski
1561c10d12e3SJakub Kicinski return budget;
1562c10d12e3SJakub Kicinski }
1563c10d12e3SJakub Kicinski
nfp_nfdk_ctrl_poll(struct tasklet_struct * t)1564c10d12e3SJakub Kicinski void nfp_nfdk_ctrl_poll(struct tasklet_struct *t)
1565c10d12e3SJakub Kicinski {
1566c10d12e3SJakub Kicinski struct nfp_net_r_vector *r_vec = from_tasklet(r_vec, t, tasklet);
1567c10d12e3SJakub Kicinski
1568c10d12e3SJakub Kicinski spin_lock(&r_vec->lock);
1569c10d12e3SJakub Kicinski nfp_nfdk_tx_complete(r_vec->tx_ring, 0);
1570c10d12e3SJakub Kicinski __nfp_ctrl_tx_queued(r_vec);
1571c10d12e3SJakub Kicinski spin_unlock(&r_vec->lock);
1572c10d12e3SJakub Kicinski
1573c10d12e3SJakub Kicinski if (nfp_ctrl_rx(r_vec)) {
1574c10d12e3SJakub Kicinski nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
1575c10d12e3SJakub Kicinski } else {
1576c10d12e3SJakub Kicinski tasklet_schedule(&r_vec->tasklet);
1577c10d12e3SJakub Kicinski nn_dp_warn(&r_vec->nfp_net->dp,
1578c10d12e3SJakub Kicinski "control message budget exceeded!\n");
1579c10d12e3SJakub Kicinski }
1580c10d12e3SJakub Kicinski }
1581