1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Huawei HiNIC PCI Express Linux driver
4*4882a593Smuzhiyun * Copyright(c) 2017 Huawei Technologies Co., Ltd
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/netdevice.h>
9*4882a593Smuzhiyun #include <linux/u64_stats_sync.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/pci.h>
13*4882a593Smuzhiyun #include <linux/device.h>
14*4882a593Smuzhiyun #include <linux/dma-mapping.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/skbuff.h>
18*4882a593Smuzhiyun #include <linux/smp.h>
19*4882a593Smuzhiyun #include <asm/byteorder.h>
20*4882a593Smuzhiyun #include <linux/ip.h>
21*4882a593Smuzhiyun #include <linux/tcp.h>
22*4882a593Smuzhiyun #include <linux/sctp.h>
23*4882a593Smuzhiyun #include <linux/ipv6.h>
24*4882a593Smuzhiyun #include <net/ipv6.h>
25*4882a593Smuzhiyun #include <net/checksum.h>
26*4882a593Smuzhiyun #include <net/ip6_checksum.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include "hinic_common.h"
29*4882a593Smuzhiyun #include "hinic_hw_if.h"
30*4882a593Smuzhiyun #include "hinic_hw_wqe.h"
31*4882a593Smuzhiyun #include "hinic_hw_wq.h"
32*4882a593Smuzhiyun #include "hinic_hw_qp.h"
33*4882a593Smuzhiyun #include "hinic_hw_dev.h"
34*4882a593Smuzhiyun #include "hinic_dev.h"
35*4882a593Smuzhiyun #include "hinic_tx.h"
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define TX_IRQ_NO_PENDING 0
38*4882a593Smuzhiyun #define TX_IRQ_NO_COALESC 0
39*4882a593Smuzhiyun #define TX_IRQ_NO_LLI_TIMER 0
40*4882a593Smuzhiyun #define TX_IRQ_NO_CREDIT 0
41*4882a593Smuzhiyun #define TX_IRQ_NO_RESEND_TIMER 0
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define CI_UPDATE_NO_PENDING 0
44*4882a593Smuzhiyun #define CI_UPDATE_NO_COALESC 0
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define HW_CONS_IDX(sq) be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define MIN_SKB_LEN 32
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define MAX_PAYLOAD_OFFSET 221
51*4882a593Smuzhiyun #define TRANSPORT_OFFSET(l4_hdr, skb) ((u32)((l4_hdr) - (skb)->data))
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun union hinic_l3 {
54*4882a593Smuzhiyun struct iphdr *v4;
55*4882a593Smuzhiyun struct ipv6hdr *v6;
56*4882a593Smuzhiyun unsigned char *hdr;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun union hinic_l4 {
60*4882a593Smuzhiyun struct tcphdr *tcp;
61*4882a593Smuzhiyun struct udphdr *udp;
62*4882a593Smuzhiyun unsigned char *hdr;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun enum hinic_offload_type {
66*4882a593Smuzhiyun TX_OFFLOAD_TSO = BIT(0),
67*4882a593Smuzhiyun TX_OFFLOAD_CSUM = BIT(1),
68*4882a593Smuzhiyun TX_OFFLOAD_VLAN = BIT(2),
69*4882a593Smuzhiyun TX_OFFLOAD_INVALID = BIT(3),
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /**
73*4882a593Smuzhiyun * hinic_txq_clean_stats - Clean the statistics of specific queue
74*4882a593Smuzhiyun * @txq: Logical Tx Queue
75*4882a593Smuzhiyun **/
hinic_txq_clean_stats(struct hinic_txq * txq)76*4882a593Smuzhiyun void hinic_txq_clean_stats(struct hinic_txq *txq)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct hinic_txq_stats *txq_stats = &txq->txq_stats;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun u64_stats_update_begin(&txq_stats->syncp);
81*4882a593Smuzhiyun txq_stats->pkts = 0;
82*4882a593Smuzhiyun txq_stats->bytes = 0;
83*4882a593Smuzhiyun txq_stats->tx_busy = 0;
84*4882a593Smuzhiyun txq_stats->tx_wake = 0;
85*4882a593Smuzhiyun txq_stats->tx_dropped = 0;
86*4882a593Smuzhiyun txq_stats->big_frags_pkts = 0;
87*4882a593Smuzhiyun u64_stats_update_end(&txq_stats->syncp);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun * hinic_txq_get_stats - get statistics of Tx Queue
92*4882a593Smuzhiyun * @txq: Logical Tx Queue
93*4882a593Smuzhiyun * @stats: return updated stats here
94*4882a593Smuzhiyun **/
hinic_txq_get_stats(struct hinic_txq * txq,struct hinic_txq_stats * stats)95*4882a593Smuzhiyun void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun struct hinic_txq_stats *txq_stats = &txq->txq_stats;
98*4882a593Smuzhiyun unsigned int start;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun do {
101*4882a593Smuzhiyun start = u64_stats_fetch_begin_irq(&txq_stats->syncp);
102*4882a593Smuzhiyun stats->pkts = txq_stats->pkts;
103*4882a593Smuzhiyun stats->bytes = txq_stats->bytes;
104*4882a593Smuzhiyun stats->tx_busy = txq_stats->tx_busy;
105*4882a593Smuzhiyun stats->tx_wake = txq_stats->tx_wake;
106*4882a593Smuzhiyun stats->tx_dropped = txq_stats->tx_dropped;
107*4882a593Smuzhiyun stats->big_frags_pkts = txq_stats->big_frags_pkts;
108*4882a593Smuzhiyun } while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start));
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /**
112*4882a593Smuzhiyun * txq_stats_init - Initialize the statistics of specific queue
113*4882a593Smuzhiyun * @txq: Logical Tx Queue
114*4882a593Smuzhiyun **/
txq_stats_init(struct hinic_txq * txq)115*4882a593Smuzhiyun static void txq_stats_init(struct hinic_txq *txq)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct hinic_txq_stats *txq_stats = &txq->txq_stats;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun u64_stats_init(&txq_stats->syncp);
120*4882a593Smuzhiyun hinic_txq_clean_stats(txq);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /**
124*4882a593Smuzhiyun * tx_map_skb - dma mapping for skb and return sges
125*4882a593Smuzhiyun * @nic_dev: nic device
126*4882a593Smuzhiyun * @skb: the skb
127*4882a593Smuzhiyun * @sges: returned sges
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * Return 0 - Success, negative - Failure
130*4882a593Smuzhiyun **/
tx_map_skb(struct hinic_dev * nic_dev,struct sk_buff * skb,struct hinic_sge * sges)131*4882a593Smuzhiyun static int tx_map_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
132*4882a593Smuzhiyun struct hinic_sge *sges)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct hinic_hwdev *hwdev = nic_dev->hwdev;
135*4882a593Smuzhiyun struct hinic_hwif *hwif = hwdev->hwif;
136*4882a593Smuzhiyun struct pci_dev *pdev = hwif->pdev;
137*4882a593Smuzhiyun skb_frag_t *frag;
138*4882a593Smuzhiyun dma_addr_t dma_addr;
139*4882a593Smuzhiyun int i, j;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun dma_addr = dma_map_single(&pdev->dev, skb->data, skb_headlen(skb),
142*4882a593Smuzhiyun DMA_TO_DEVICE);
143*4882a593Smuzhiyun if (dma_mapping_error(&pdev->dev, dma_addr)) {
144*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to map Tx skb data\n");
145*4882a593Smuzhiyun return -EFAULT;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun hinic_set_sge(&sges[0], dma_addr, skb_headlen(skb));
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun for (i = 0 ; i < skb_shinfo(skb)->nr_frags; i++) {
151*4882a593Smuzhiyun frag = &skb_shinfo(skb)->frags[i];
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun dma_addr = skb_frag_dma_map(&pdev->dev, frag, 0,
154*4882a593Smuzhiyun skb_frag_size(frag),
155*4882a593Smuzhiyun DMA_TO_DEVICE);
156*4882a593Smuzhiyun if (dma_mapping_error(&pdev->dev, dma_addr)) {
157*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to map Tx skb frag\n");
158*4882a593Smuzhiyun goto err_tx_map;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun hinic_set_sge(&sges[i + 1], dma_addr, skb_frag_size(frag));
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun err_tx_map:
167*4882a593Smuzhiyun for (j = 0; j < i; j++)
168*4882a593Smuzhiyun dma_unmap_page(&pdev->dev, hinic_sge_to_dma(&sges[j + 1]),
169*4882a593Smuzhiyun sges[j + 1].len, DMA_TO_DEVICE);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun dma_unmap_single(&pdev->dev, hinic_sge_to_dma(&sges[0]), sges[0].len,
172*4882a593Smuzhiyun DMA_TO_DEVICE);
173*4882a593Smuzhiyun return -EFAULT;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /**
177*4882a593Smuzhiyun * tx_unmap_skb - unmap the dma address of the skb
178*4882a593Smuzhiyun * @nic_dev: nic device
179*4882a593Smuzhiyun * @skb: the skb
180*4882a593Smuzhiyun * @sges: the sges that are connected to the skb
181*4882a593Smuzhiyun **/
tx_unmap_skb(struct hinic_dev * nic_dev,struct sk_buff * skb,struct hinic_sge * sges)182*4882a593Smuzhiyun static void tx_unmap_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
183*4882a593Smuzhiyun struct hinic_sge *sges)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct hinic_hwdev *hwdev = nic_dev->hwdev;
186*4882a593Smuzhiyun struct hinic_hwif *hwif = hwdev->hwif;
187*4882a593Smuzhiyun struct pci_dev *pdev = hwif->pdev;
188*4882a593Smuzhiyun int i;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun for (i = 0; i < skb_shinfo(skb)->nr_frags ; i++)
191*4882a593Smuzhiyun dma_unmap_page(&pdev->dev, hinic_sge_to_dma(&sges[i + 1]),
192*4882a593Smuzhiyun sges[i + 1].len, DMA_TO_DEVICE);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun dma_unmap_single(&pdev->dev, hinic_sge_to_dma(&sges[0]), sges[0].len,
195*4882a593Smuzhiyun DMA_TO_DEVICE);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
get_inner_l3_l4_type(struct sk_buff * skb,union hinic_l3 * ip,union hinic_l4 * l4,enum hinic_offload_type offload_type,enum hinic_l3_offload_type * l3_type,u8 * l4_proto)198*4882a593Smuzhiyun static void get_inner_l3_l4_type(struct sk_buff *skb, union hinic_l3 *ip,
199*4882a593Smuzhiyun union hinic_l4 *l4,
200*4882a593Smuzhiyun enum hinic_offload_type offload_type,
201*4882a593Smuzhiyun enum hinic_l3_offload_type *l3_type,
202*4882a593Smuzhiyun u8 *l4_proto)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun u8 *exthdr;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (ip->v4->version == 4) {
207*4882a593Smuzhiyun *l3_type = (offload_type == TX_OFFLOAD_CSUM) ?
208*4882a593Smuzhiyun IPV4_PKT_NO_CHKSUM_OFFLOAD :
209*4882a593Smuzhiyun IPV4_PKT_WITH_CHKSUM_OFFLOAD;
210*4882a593Smuzhiyun *l4_proto = ip->v4->protocol;
211*4882a593Smuzhiyun } else if (ip->v4->version == 6) {
212*4882a593Smuzhiyun *l3_type = IPV6_PKT;
213*4882a593Smuzhiyun exthdr = ip->hdr + sizeof(*ip->v6);
214*4882a593Smuzhiyun *l4_proto = ip->v6->nexthdr;
215*4882a593Smuzhiyun if (exthdr != l4->hdr) {
216*4882a593Smuzhiyun int start = exthdr - skb->data;
217*4882a593Smuzhiyun __be16 frag_off;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun ipv6_skip_exthdr(skb, start, l4_proto, &frag_off);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun } else {
222*4882a593Smuzhiyun *l3_type = L3TYPE_UNKNOWN;
223*4882a593Smuzhiyun *l4_proto = 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
get_inner_l4_info(struct sk_buff * skb,union hinic_l4 * l4,enum hinic_offload_type offload_type,u8 l4_proto,enum hinic_l4_offload_type * l4_offload,u32 * l4_len,u32 * offset)227*4882a593Smuzhiyun static void get_inner_l4_info(struct sk_buff *skb, union hinic_l4 *l4,
228*4882a593Smuzhiyun enum hinic_offload_type offload_type, u8 l4_proto,
229*4882a593Smuzhiyun enum hinic_l4_offload_type *l4_offload,
230*4882a593Smuzhiyun u32 *l4_len, u32 *offset)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun *l4_offload = OFFLOAD_DISABLE;
233*4882a593Smuzhiyun *offset = 0;
234*4882a593Smuzhiyun *l4_len = 0;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun switch (l4_proto) {
237*4882a593Smuzhiyun case IPPROTO_TCP:
238*4882a593Smuzhiyun *l4_offload = TCP_OFFLOAD_ENABLE;
239*4882a593Smuzhiyun /* doff in unit of 4B */
240*4882a593Smuzhiyun *l4_len = l4->tcp->doff * 4;
241*4882a593Smuzhiyun *offset = *l4_len + TRANSPORT_OFFSET(l4->hdr, skb);
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun case IPPROTO_UDP:
245*4882a593Smuzhiyun *l4_offload = UDP_OFFLOAD_ENABLE;
246*4882a593Smuzhiyun *l4_len = sizeof(struct udphdr);
247*4882a593Smuzhiyun *offset = TRANSPORT_OFFSET(l4->hdr, skb);
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun case IPPROTO_SCTP:
251*4882a593Smuzhiyun /* only csum offload support sctp */
252*4882a593Smuzhiyun if (offload_type != TX_OFFLOAD_CSUM)
253*4882a593Smuzhiyun break;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun *l4_offload = SCTP_OFFLOAD_ENABLE;
256*4882a593Smuzhiyun *l4_len = sizeof(struct sctphdr);
257*4882a593Smuzhiyun *offset = TRANSPORT_OFFSET(l4->hdr, skb);
258*4882a593Smuzhiyun break;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun default:
261*4882a593Smuzhiyun break;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
csum_magic(union hinic_l3 * ip,unsigned short proto)265*4882a593Smuzhiyun static __sum16 csum_magic(union hinic_l3 *ip, unsigned short proto)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun return (ip->v4->version == 4) ?
268*4882a593Smuzhiyun csum_tcpudp_magic(ip->v4->saddr, ip->v4->daddr, 0, proto, 0) :
269*4882a593Smuzhiyun csum_ipv6_magic(&ip->v6->saddr, &ip->v6->daddr, 0, proto, 0);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
offload_tso(struct hinic_sq_task * task,u32 * queue_info,struct sk_buff * skb)272*4882a593Smuzhiyun static int offload_tso(struct hinic_sq_task *task, u32 *queue_info,
273*4882a593Smuzhiyun struct sk_buff *skb)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun u32 offset, l4_len, ip_identify, network_hdr_len;
276*4882a593Smuzhiyun enum hinic_l3_offload_type l3_offload;
277*4882a593Smuzhiyun enum hinic_l4_offload_type l4_offload;
278*4882a593Smuzhiyun union hinic_l3 ip;
279*4882a593Smuzhiyun union hinic_l4 l4;
280*4882a593Smuzhiyun u8 l4_proto;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (!skb_is_gso(skb))
283*4882a593Smuzhiyun return 0;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (skb_cow_head(skb, 0) < 0)
286*4882a593Smuzhiyun return -EPROTONOSUPPORT;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (skb->encapsulation) {
289*4882a593Smuzhiyun u32 gso_type = skb_shinfo(skb)->gso_type;
290*4882a593Smuzhiyun u32 tunnel_type = 0;
291*4882a593Smuzhiyun u32 l4_tunnel_len;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun ip.hdr = skb_network_header(skb);
294*4882a593Smuzhiyun l4.hdr = skb_transport_header(skb);
295*4882a593Smuzhiyun network_hdr_len = skb_inner_network_header_len(skb);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun if (ip.v4->version == 4) {
298*4882a593Smuzhiyun ip.v4->tot_len = 0;
299*4882a593Smuzhiyun l3_offload = IPV4_PKT_WITH_CHKSUM_OFFLOAD;
300*4882a593Smuzhiyun } else if (ip.v4->version == 6) {
301*4882a593Smuzhiyun l3_offload = IPV6_PKT;
302*4882a593Smuzhiyun } else {
303*4882a593Smuzhiyun l3_offload = 0;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun hinic_task_set_outter_l3(task, l3_offload,
307*4882a593Smuzhiyun skb_network_header_len(skb));
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
310*4882a593Smuzhiyun l4.udp->check = ~csum_magic(&ip, IPPROTO_UDP);
311*4882a593Smuzhiyun tunnel_type = TUNNEL_UDP_CSUM;
312*4882a593Smuzhiyun } else if (gso_type & SKB_GSO_UDP_TUNNEL) {
313*4882a593Smuzhiyun tunnel_type = TUNNEL_UDP_NO_CSUM;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun l4_tunnel_len = skb_inner_network_offset(skb) -
317*4882a593Smuzhiyun skb_transport_offset(skb);
318*4882a593Smuzhiyun hinic_task_set_tunnel_l4(task, tunnel_type, l4_tunnel_len);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun ip.hdr = skb_inner_network_header(skb);
321*4882a593Smuzhiyun l4.hdr = skb_inner_transport_header(skb);
322*4882a593Smuzhiyun } else {
323*4882a593Smuzhiyun ip.hdr = skb_network_header(skb);
324*4882a593Smuzhiyun l4.hdr = skb_transport_header(skb);
325*4882a593Smuzhiyun network_hdr_len = skb_network_header_len(skb);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun /* initialize inner IP header fields */
329*4882a593Smuzhiyun if (ip.v4->version == 4)
330*4882a593Smuzhiyun ip.v4->tot_len = 0;
331*4882a593Smuzhiyun else
332*4882a593Smuzhiyun ip.v6->payload_len = 0;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_TSO, &l3_offload,
335*4882a593Smuzhiyun &l4_proto);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun hinic_task_set_inner_l3(task, l3_offload, network_hdr_len);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun ip_identify = 0;
340*4882a593Smuzhiyun if (l4_proto == IPPROTO_TCP)
341*4882a593Smuzhiyun l4.tcp->check = ~csum_magic(&ip, IPPROTO_TCP);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun get_inner_l4_info(skb, &l4, TX_OFFLOAD_TSO, l4_proto, &l4_offload,
344*4882a593Smuzhiyun &l4_len, &offset);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun hinic_set_tso_inner_l4(task, queue_info, l4_offload, l4_len, offset,
347*4882a593Smuzhiyun ip_identify, skb_shinfo(skb)->gso_size);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun return 1;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
offload_csum(struct hinic_sq_task * task,u32 * queue_info,struct sk_buff * skb)352*4882a593Smuzhiyun static int offload_csum(struct hinic_sq_task *task, u32 *queue_info,
353*4882a593Smuzhiyun struct sk_buff *skb)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun enum hinic_l4_offload_type l4_offload;
356*4882a593Smuzhiyun u32 offset, l4_len, network_hdr_len;
357*4882a593Smuzhiyun enum hinic_l3_offload_type l3_type;
358*4882a593Smuzhiyun u32 tunnel_type = NOT_TUNNEL;
359*4882a593Smuzhiyun union hinic_l3 ip;
360*4882a593Smuzhiyun union hinic_l4 l4;
361*4882a593Smuzhiyun u8 l4_proto;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (skb->ip_summed != CHECKSUM_PARTIAL)
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (skb->encapsulation) {
367*4882a593Smuzhiyun u32 l4_tunnel_len;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun tunnel_type = TUNNEL_UDP_NO_CSUM;
370*4882a593Smuzhiyun ip.hdr = skb_network_header(skb);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (ip.v4->version == 4) {
373*4882a593Smuzhiyun l3_type = IPV4_PKT_NO_CHKSUM_OFFLOAD;
374*4882a593Smuzhiyun l4_proto = ip.v4->protocol;
375*4882a593Smuzhiyun } else if (ip.v4->version == 6) {
376*4882a593Smuzhiyun unsigned char *exthdr;
377*4882a593Smuzhiyun __be16 frag_off;
378*4882a593Smuzhiyun l3_type = IPV6_PKT;
379*4882a593Smuzhiyun tunnel_type = TUNNEL_UDP_CSUM;
380*4882a593Smuzhiyun exthdr = ip.hdr + sizeof(*ip.v6);
381*4882a593Smuzhiyun l4_proto = ip.v6->nexthdr;
382*4882a593Smuzhiyun l4.hdr = skb_transport_header(skb);
383*4882a593Smuzhiyun if (l4.hdr != exthdr)
384*4882a593Smuzhiyun ipv6_skip_exthdr(skb, exthdr - skb->data,
385*4882a593Smuzhiyun &l4_proto, &frag_off);
386*4882a593Smuzhiyun } else {
387*4882a593Smuzhiyun l3_type = L3TYPE_UNKNOWN;
388*4882a593Smuzhiyun l4_proto = IPPROTO_RAW;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun hinic_task_set_outter_l3(task, l3_type,
392*4882a593Smuzhiyun skb_network_header_len(skb));
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun switch (l4_proto) {
395*4882a593Smuzhiyun case IPPROTO_UDP:
396*4882a593Smuzhiyun l4_tunnel_len = skb_inner_network_offset(skb) -
397*4882a593Smuzhiyun skb_transport_offset(skb);
398*4882a593Smuzhiyun ip.hdr = skb_inner_network_header(skb);
399*4882a593Smuzhiyun l4.hdr = skb_inner_transport_header(skb);
400*4882a593Smuzhiyun network_hdr_len = skb_inner_network_header_len(skb);
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun case IPPROTO_IPIP:
403*4882a593Smuzhiyun case IPPROTO_IPV6:
404*4882a593Smuzhiyun tunnel_type = NOT_TUNNEL;
405*4882a593Smuzhiyun l4_tunnel_len = 0;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun ip.hdr = skb_inner_network_header(skb);
408*4882a593Smuzhiyun l4.hdr = skb_transport_header(skb);
409*4882a593Smuzhiyun network_hdr_len = skb_network_header_len(skb);
410*4882a593Smuzhiyun break;
411*4882a593Smuzhiyun default:
412*4882a593Smuzhiyun /* Unsupported tunnel packet, disable csum offload */
413*4882a593Smuzhiyun skb_checksum_help(skb);
414*4882a593Smuzhiyun return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun hinic_task_set_tunnel_l4(task, tunnel_type, l4_tunnel_len);
418*4882a593Smuzhiyun } else {
419*4882a593Smuzhiyun ip.hdr = skb_network_header(skb);
420*4882a593Smuzhiyun l4.hdr = skb_transport_header(skb);
421*4882a593Smuzhiyun network_hdr_len = skb_network_header_len(skb);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_CSUM, &l3_type,
425*4882a593Smuzhiyun &l4_proto);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun hinic_task_set_inner_l3(task, l3_type, network_hdr_len);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun get_inner_l4_info(skb, &l4, TX_OFFLOAD_CSUM, l4_proto, &l4_offload,
430*4882a593Smuzhiyun &l4_len, &offset);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun hinic_set_cs_inner_l4(task, queue_info, l4_offload, l4_len, offset);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return 1;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
offload_vlan(struct hinic_sq_task * task,u32 * queue_info,u16 vlan_tag,u16 vlan_pri)437*4882a593Smuzhiyun static void offload_vlan(struct hinic_sq_task *task, u32 *queue_info,
438*4882a593Smuzhiyun u16 vlan_tag, u16 vlan_pri)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(vlan_tag, VLAN_TAG) |
441*4882a593Smuzhiyun HINIC_SQ_TASK_INFO0_SET(1U, VLAN_OFFLOAD);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun *queue_info |= HINIC_SQ_CTRL_SET(vlan_pri, QUEUE_INFO_PRI);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
hinic_tx_offload(struct sk_buff * skb,struct hinic_sq_task * task,u32 * queue_info)446*4882a593Smuzhiyun static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
447*4882a593Smuzhiyun u32 *queue_info)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun enum hinic_offload_type offload = 0;
450*4882a593Smuzhiyun u16 vlan_tag;
451*4882a593Smuzhiyun int enabled;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun enabled = offload_tso(task, queue_info, skb);
454*4882a593Smuzhiyun if (enabled > 0) {
455*4882a593Smuzhiyun offload |= TX_OFFLOAD_TSO;
456*4882a593Smuzhiyun } else if (enabled == 0) {
457*4882a593Smuzhiyun enabled = offload_csum(task, queue_info, skb);
458*4882a593Smuzhiyun if (enabled)
459*4882a593Smuzhiyun offload |= TX_OFFLOAD_CSUM;
460*4882a593Smuzhiyun } else {
461*4882a593Smuzhiyun return -EPROTONOSUPPORT;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (unlikely(skb_vlan_tag_present(skb))) {
465*4882a593Smuzhiyun vlan_tag = skb_vlan_tag_get(skb);
466*4882a593Smuzhiyun offload_vlan(task, queue_info, vlan_tag,
467*4882a593Smuzhiyun vlan_tag >> VLAN_PRIO_SHIFT);
468*4882a593Smuzhiyun offload |= TX_OFFLOAD_VLAN;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun if (offload)
472*4882a593Smuzhiyun hinic_task_set_l2hdr(task, skb_network_offset(skb));
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /* payload offset should not more than 221 */
475*4882a593Smuzhiyun if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_PLDOFF) >
476*4882a593Smuzhiyun MAX_PAYLOAD_OFFSET) {
477*4882a593Smuzhiyun return -EPROTONOSUPPORT;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /* mss should not less than 80 */
481*4882a593Smuzhiyun if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_MSS) < HINIC_MSS_MIN) {
482*4882a593Smuzhiyun *queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
483*4882a593Smuzhiyun *queue_info |= HINIC_SQ_CTRL_SET(HINIC_MSS_MIN, QUEUE_INFO_MSS);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
hinic_lb_xmit_frame(struct sk_buff * skb,struct net_device * netdev)489*4882a593Smuzhiyun netdev_tx_t hinic_lb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(netdev);
492*4882a593Smuzhiyun u16 prod_idx, q_id = skb->queue_mapping;
493*4882a593Smuzhiyun struct netdev_queue *netdev_txq;
494*4882a593Smuzhiyun int nr_sges, err = NETDEV_TX_OK;
495*4882a593Smuzhiyun struct hinic_sq_wqe *sq_wqe;
496*4882a593Smuzhiyun unsigned int wqe_size;
497*4882a593Smuzhiyun struct hinic_txq *txq;
498*4882a593Smuzhiyun struct hinic_qp *qp;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun txq = &nic_dev->txqs[q_id];
501*4882a593Smuzhiyun qp = container_of(txq->sq, struct hinic_qp, sq);
502*4882a593Smuzhiyun nr_sges = skb_shinfo(skb)->nr_frags + 1;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun err = tx_map_skb(nic_dev, skb, txq->sges);
505*4882a593Smuzhiyun if (err)
506*4882a593Smuzhiyun goto skb_error;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun wqe_size = HINIC_SQ_WQE_SIZE(nr_sges);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun sq_wqe = hinic_sq_get_wqe(txq->sq, wqe_size, &prod_idx);
511*4882a593Smuzhiyun if (!sq_wqe) {
512*4882a593Smuzhiyun netif_stop_subqueue(netdev, qp->q_id);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun sq_wqe = hinic_sq_get_wqe(txq->sq, wqe_size, &prod_idx);
515*4882a593Smuzhiyun if (sq_wqe) {
516*4882a593Smuzhiyun netif_wake_subqueue(nic_dev->netdev, qp->q_id);
517*4882a593Smuzhiyun goto process_sq_wqe;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun tx_unmap_skb(nic_dev, skb, txq->sges);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
523*4882a593Smuzhiyun txq->txq_stats.tx_busy++;
524*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
525*4882a593Smuzhiyun err = NETDEV_TX_BUSY;
526*4882a593Smuzhiyun wqe_size = 0;
527*4882a593Smuzhiyun goto flush_skbs;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun process_sq_wqe:
531*4882a593Smuzhiyun hinic_sq_prepare_wqe(txq->sq, prod_idx, sq_wqe, txq->sges, nr_sges);
532*4882a593Smuzhiyun hinic_sq_write_wqe(txq->sq, prod_idx, sq_wqe, skb, wqe_size);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun flush_skbs:
535*4882a593Smuzhiyun netdev_txq = netdev_get_tx_queue(netdev, q_id);
536*4882a593Smuzhiyun if ((!netdev_xmit_more()) || (netif_xmit_stopped(netdev_txq)))
537*4882a593Smuzhiyun hinic_sq_write_db(txq->sq, prod_idx, wqe_size, 0);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun return err;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun skb_error:
542*4882a593Smuzhiyun dev_kfree_skb_any(skb);
543*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
544*4882a593Smuzhiyun txq->txq_stats.tx_dropped++;
545*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return NETDEV_TX_OK;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
hinic_xmit_frame(struct sk_buff * skb,struct net_device * netdev)550*4882a593Smuzhiyun netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(netdev);
553*4882a593Smuzhiyun u16 prod_idx, q_id = skb->queue_mapping;
554*4882a593Smuzhiyun struct netdev_queue *netdev_txq;
555*4882a593Smuzhiyun int nr_sges, err = NETDEV_TX_OK;
556*4882a593Smuzhiyun struct hinic_sq_wqe *sq_wqe;
557*4882a593Smuzhiyun unsigned int wqe_size;
558*4882a593Smuzhiyun struct hinic_txq *txq;
559*4882a593Smuzhiyun struct hinic_qp *qp;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun txq = &nic_dev->txqs[q_id];
562*4882a593Smuzhiyun qp = container_of(txq->sq, struct hinic_qp, sq);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if (skb->len < MIN_SKB_LEN) {
565*4882a593Smuzhiyun if (skb_pad(skb, MIN_SKB_LEN - skb->len)) {
566*4882a593Smuzhiyun netdev_err(netdev, "Failed to pad skb\n");
567*4882a593Smuzhiyun goto update_error_stats;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun skb->len = MIN_SKB_LEN;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun nr_sges = skb_shinfo(skb)->nr_frags + 1;
574*4882a593Smuzhiyun if (nr_sges > 17) {
575*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
576*4882a593Smuzhiyun txq->txq_stats.big_frags_pkts++;
577*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun if (nr_sges > txq->max_sges) {
581*4882a593Smuzhiyun netdev_err(netdev, "Too many Tx sges\n");
582*4882a593Smuzhiyun goto skb_error;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun err = tx_map_skb(nic_dev, skb, txq->sges);
586*4882a593Smuzhiyun if (err)
587*4882a593Smuzhiyun goto skb_error;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun wqe_size = HINIC_SQ_WQE_SIZE(nr_sges);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun sq_wqe = hinic_sq_get_wqe(txq->sq, wqe_size, &prod_idx);
592*4882a593Smuzhiyun if (!sq_wqe) {
593*4882a593Smuzhiyun netif_stop_subqueue(netdev, qp->q_id);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun /* Check for the case free_tx_poll is called in another cpu
596*4882a593Smuzhiyun * and we stopped the subqueue after free_tx_poll check.
597*4882a593Smuzhiyun */
598*4882a593Smuzhiyun sq_wqe = hinic_sq_get_wqe(txq->sq, wqe_size, &prod_idx);
599*4882a593Smuzhiyun if (sq_wqe) {
600*4882a593Smuzhiyun netif_wake_subqueue(nic_dev->netdev, qp->q_id);
601*4882a593Smuzhiyun goto process_sq_wqe;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun tx_unmap_skb(nic_dev, skb, txq->sges);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
607*4882a593Smuzhiyun txq->txq_stats.tx_busy++;
608*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
609*4882a593Smuzhiyun err = NETDEV_TX_BUSY;
610*4882a593Smuzhiyun wqe_size = 0;
611*4882a593Smuzhiyun goto flush_skbs;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun process_sq_wqe:
615*4882a593Smuzhiyun hinic_sq_prepare_wqe(txq->sq, prod_idx, sq_wqe, txq->sges, nr_sges);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun err = hinic_tx_offload(skb, &sq_wqe->task, &sq_wqe->ctrl.queue_info);
618*4882a593Smuzhiyun if (err)
619*4882a593Smuzhiyun goto offload_error;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun hinic_sq_write_wqe(txq->sq, prod_idx, sq_wqe, skb, wqe_size);
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun flush_skbs:
624*4882a593Smuzhiyun netdev_txq = netdev_get_tx_queue(netdev, q_id);
625*4882a593Smuzhiyun if ((!netdev_xmit_more()) || (netif_xmit_stopped(netdev_txq)))
626*4882a593Smuzhiyun hinic_sq_write_db(txq->sq, prod_idx, wqe_size, 0);
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun return err;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun offload_error:
631*4882a593Smuzhiyun hinic_sq_return_wqe(txq->sq, wqe_size);
632*4882a593Smuzhiyun tx_unmap_skb(nic_dev, skb, txq->sges);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun skb_error:
635*4882a593Smuzhiyun dev_kfree_skb_any(skb);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun update_error_stats:
638*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
639*4882a593Smuzhiyun txq->txq_stats.tx_dropped++;
640*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun return NETDEV_TX_OK;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /**
646*4882a593Smuzhiyun * tx_free_skb - unmap and free skb
647*4882a593Smuzhiyun * @nic_dev: nic device
648*4882a593Smuzhiyun * @skb: the skb
649*4882a593Smuzhiyun * @sges: the sges that are connected to the skb
650*4882a593Smuzhiyun **/
tx_free_skb(struct hinic_dev * nic_dev,struct sk_buff * skb,struct hinic_sge * sges)651*4882a593Smuzhiyun static void tx_free_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
652*4882a593Smuzhiyun struct hinic_sge *sges)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun tx_unmap_skb(nic_dev, skb, sges);
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun dev_kfree_skb_any(skb);
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun /**
660*4882a593Smuzhiyun * free_all_rx_skbs - free all skbs in tx queue
661*4882a593Smuzhiyun * @txq: tx queue
662*4882a593Smuzhiyun **/
free_all_tx_skbs(struct hinic_txq * txq)663*4882a593Smuzhiyun static void free_all_tx_skbs(struct hinic_txq *txq)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(txq->netdev);
666*4882a593Smuzhiyun struct hinic_sq *sq = txq->sq;
667*4882a593Smuzhiyun struct hinic_sq_wqe *sq_wqe;
668*4882a593Smuzhiyun unsigned int wqe_size;
669*4882a593Smuzhiyun struct sk_buff *skb;
670*4882a593Smuzhiyun int nr_sges;
671*4882a593Smuzhiyun u16 ci;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun while ((sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &ci))) {
674*4882a593Smuzhiyun sq_wqe = hinic_sq_read_wqe(sq, &skb, wqe_size, &ci);
675*4882a593Smuzhiyun if (!sq_wqe)
676*4882a593Smuzhiyun break;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun nr_sges = skb_shinfo(skb)->nr_frags + 1;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun hinic_sq_get_sges(sq_wqe, txq->free_sges, nr_sges);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun hinic_sq_put_wqe(sq, wqe_size);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun tx_free_skb(nic_dev, skb, txq->free_sges);
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun /**
689*4882a593Smuzhiyun * free_tx_poll - free finished tx skbs in tx queue that connected to napi
690*4882a593Smuzhiyun * @napi: napi
691*4882a593Smuzhiyun * @budget: number of tx
692*4882a593Smuzhiyun *
693*4882a593Smuzhiyun * Return 0 - Success, negative - Failure
694*4882a593Smuzhiyun **/
free_tx_poll(struct napi_struct * napi,int budget)695*4882a593Smuzhiyun static int free_tx_poll(struct napi_struct *napi, int budget)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun struct hinic_txq *txq = container_of(napi, struct hinic_txq, napi);
698*4882a593Smuzhiyun struct hinic_qp *qp = container_of(txq->sq, struct hinic_qp, sq);
699*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(txq->netdev);
700*4882a593Smuzhiyun struct netdev_queue *netdev_txq;
701*4882a593Smuzhiyun struct hinic_sq *sq = txq->sq;
702*4882a593Smuzhiyun struct hinic_wq *wq = sq->wq;
703*4882a593Smuzhiyun struct hinic_sq_wqe *sq_wqe;
704*4882a593Smuzhiyun unsigned int wqe_size;
705*4882a593Smuzhiyun int nr_sges, pkts = 0;
706*4882a593Smuzhiyun struct sk_buff *skb;
707*4882a593Smuzhiyun u64 tx_bytes = 0;
708*4882a593Smuzhiyun u16 hw_ci, sw_ci;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun do {
711*4882a593Smuzhiyun hw_ci = HW_CONS_IDX(sq) & wq->mask;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun dma_rmb();
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun /* Reading a WQEBB to get real WQE size and consumer index. */
716*4882a593Smuzhiyun sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &sw_ci);
717*4882a593Smuzhiyun if ((!sq_wqe) ||
718*4882a593Smuzhiyun (((hw_ci - sw_ci) & wq->mask) * wq->wqebb_size < wqe_size))
719*4882a593Smuzhiyun break;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun /* If this WQE have multiple WQEBBs, we will read again to get
722*4882a593Smuzhiyun * full size WQE.
723*4882a593Smuzhiyun */
724*4882a593Smuzhiyun if (wqe_size > wq->wqebb_size) {
725*4882a593Smuzhiyun sq_wqe = hinic_sq_read_wqe(sq, &skb, wqe_size, &sw_ci);
726*4882a593Smuzhiyun if (unlikely(!sq_wqe))
727*4882a593Smuzhiyun break;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun tx_bytes += skb->len;
731*4882a593Smuzhiyun pkts++;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun nr_sges = skb_shinfo(skb)->nr_frags + 1;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun hinic_sq_get_sges(sq_wqe, txq->free_sges, nr_sges);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun hinic_sq_put_wqe(sq, wqe_size);
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun tx_free_skb(nic_dev, skb, txq->free_sges);
740*4882a593Smuzhiyun } while (pkts < budget);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun if (__netif_subqueue_stopped(nic_dev->netdev, qp->q_id) &&
743*4882a593Smuzhiyun hinic_get_sq_free_wqebbs(sq) >= HINIC_MIN_TX_NUM_WQEBBS(sq)) {
744*4882a593Smuzhiyun netdev_txq = netdev_get_tx_queue(txq->netdev, qp->q_id);
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun __netif_tx_lock(netdev_txq, smp_processor_id());
747*4882a593Smuzhiyun if (!netif_testing(nic_dev->netdev))
748*4882a593Smuzhiyun netif_wake_subqueue(nic_dev->netdev, qp->q_id);
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun __netif_tx_unlock(netdev_txq);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
753*4882a593Smuzhiyun txq->txq_stats.tx_wake++;
754*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun u64_stats_update_begin(&txq->txq_stats.syncp);
758*4882a593Smuzhiyun txq->txq_stats.bytes += tx_bytes;
759*4882a593Smuzhiyun txq->txq_stats.pkts += pkts;
760*4882a593Smuzhiyun u64_stats_update_end(&txq->txq_stats.syncp);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun if (pkts < budget) {
763*4882a593Smuzhiyun napi_complete(napi);
764*4882a593Smuzhiyun if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
765*4882a593Smuzhiyun hinic_hwdev_set_msix_state(nic_dev->hwdev,
766*4882a593Smuzhiyun sq->msix_entry,
767*4882a593Smuzhiyun HINIC_MSIX_ENABLE);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun return pkts;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun return budget;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
tx_irq(int irq,void * data)775*4882a593Smuzhiyun static irqreturn_t tx_irq(int irq, void *data)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun struct hinic_txq *txq = data;
778*4882a593Smuzhiyun struct hinic_dev *nic_dev;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun nic_dev = netdev_priv(txq->netdev);
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
783*4882a593Smuzhiyun /* Disable the interrupt until napi will be completed */
784*4882a593Smuzhiyun hinic_hwdev_set_msix_state(nic_dev->hwdev,
785*4882a593Smuzhiyun txq->sq->msix_entry,
786*4882a593Smuzhiyun HINIC_MSIX_DISABLE);
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun hinic_hwdev_msix_cnt_set(nic_dev->hwdev, txq->sq->msix_entry);
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun napi_schedule(&txq->napi);
791*4882a593Smuzhiyun return IRQ_HANDLED;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
tx_request_irq(struct hinic_txq * txq)794*4882a593Smuzhiyun static int tx_request_irq(struct hinic_txq *txq)
795*4882a593Smuzhiyun {
796*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(txq->netdev);
797*4882a593Smuzhiyun struct hinic_msix_config interrupt_info = {0};
798*4882a593Smuzhiyun struct hinic_intr_coal_info *intr_coal = NULL;
799*4882a593Smuzhiyun struct hinic_hwdev *hwdev = nic_dev->hwdev;
800*4882a593Smuzhiyun struct hinic_hwif *hwif = hwdev->hwif;
801*4882a593Smuzhiyun struct pci_dev *pdev = hwif->pdev;
802*4882a593Smuzhiyun struct hinic_sq *sq = txq->sq;
803*4882a593Smuzhiyun struct hinic_qp *qp;
804*4882a593Smuzhiyun int err;
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun qp = container_of(sq, struct hinic_qp, sq);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun netif_napi_add(txq->netdev, &txq->napi, free_tx_poll, nic_dev->tx_weight);
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun hinic_hwdev_msix_set(nic_dev->hwdev, sq->msix_entry,
811*4882a593Smuzhiyun TX_IRQ_NO_PENDING, TX_IRQ_NO_COALESC,
812*4882a593Smuzhiyun TX_IRQ_NO_LLI_TIMER, TX_IRQ_NO_CREDIT,
813*4882a593Smuzhiyun TX_IRQ_NO_RESEND_TIMER);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun intr_coal = &nic_dev->tx_intr_coalesce[qp->q_id];
816*4882a593Smuzhiyun interrupt_info.msix_index = sq->msix_entry;
817*4882a593Smuzhiyun interrupt_info.coalesce_timer_cnt = intr_coal->coalesce_timer_cfg;
818*4882a593Smuzhiyun interrupt_info.pending_cnt = intr_coal->pending_limt;
819*4882a593Smuzhiyun interrupt_info.resend_timer_cnt = intr_coal->resend_timer_cfg;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun err = hinic_set_interrupt_cfg(hwdev, &interrupt_info);
822*4882a593Smuzhiyun if (err) {
823*4882a593Smuzhiyun netif_err(nic_dev, drv, txq->netdev,
824*4882a593Smuzhiyun "Failed to set TX interrupt coalescing attribute\n");
825*4882a593Smuzhiyun netif_napi_del(&txq->napi);
826*4882a593Smuzhiyun return err;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun err = request_irq(sq->irq, tx_irq, 0, txq->irq_name, txq);
830*4882a593Smuzhiyun if (err) {
831*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to request Tx irq\n");
832*4882a593Smuzhiyun netif_napi_del(&txq->napi);
833*4882a593Smuzhiyun return err;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun return 0;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun
tx_free_irq(struct hinic_txq * txq)839*4882a593Smuzhiyun static void tx_free_irq(struct hinic_txq *txq)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun struct hinic_sq *sq = txq->sq;
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun free_irq(sq->irq, txq);
844*4882a593Smuzhiyun netif_napi_del(&txq->napi);
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun /**
848*4882a593Smuzhiyun * hinic_init_txq - Initialize the Tx Queue
849*4882a593Smuzhiyun * @txq: Logical Tx Queue
850*4882a593Smuzhiyun * @sq: Hardware Tx Queue to connect the Logical queue with
851*4882a593Smuzhiyun * @netdev: network device to connect the Logical queue with
852*4882a593Smuzhiyun *
853*4882a593Smuzhiyun * Return 0 - Success, negative - Failure
854*4882a593Smuzhiyun **/
hinic_init_txq(struct hinic_txq * txq,struct hinic_sq * sq,struct net_device * netdev)855*4882a593Smuzhiyun int hinic_init_txq(struct hinic_txq *txq, struct hinic_sq *sq,
856*4882a593Smuzhiyun struct net_device *netdev)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun struct hinic_qp *qp = container_of(sq, struct hinic_qp, sq);
859*4882a593Smuzhiyun struct hinic_dev *nic_dev = netdev_priv(netdev);
860*4882a593Smuzhiyun struct hinic_hwdev *hwdev = nic_dev->hwdev;
861*4882a593Smuzhiyun int err, irqname_len;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun txq->netdev = netdev;
864*4882a593Smuzhiyun txq->sq = sq;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun txq_stats_init(txq);
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun txq->max_sges = HINIC_MAX_SQ_BUFDESCS;
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun txq->sges = devm_kcalloc(&netdev->dev, txq->max_sges,
871*4882a593Smuzhiyun sizeof(*txq->sges), GFP_KERNEL);
872*4882a593Smuzhiyun if (!txq->sges)
873*4882a593Smuzhiyun return -ENOMEM;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun txq->free_sges = devm_kcalloc(&netdev->dev, txq->max_sges,
876*4882a593Smuzhiyun sizeof(*txq->free_sges), GFP_KERNEL);
877*4882a593Smuzhiyun if (!txq->free_sges) {
878*4882a593Smuzhiyun err = -ENOMEM;
879*4882a593Smuzhiyun goto err_alloc_free_sges;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun irqname_len = snprintf(NULL, 0, "%s_txq%d", netdev->name, qp->q_id) + 1;
883*4882a593Smuzhiyun txq->irq_name = devm_kzalloc(&netdev->dev, irqname_len, GFP_KERNEL);
884*4882a593Smuzhiyun if (!txq->irq_name) {
885*4882a593Smuzhiyun err = -ENOMEM;
886*4882a593Smuzhiyun goto err_alloc_irqname;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun sprintf(txq->irq_name, "%s_txq%d", netdev->name, qp->q_id);
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun err = hinic_hwdev_hw_ci_addr_set(hwdev, sq, CI_UPDATE_NO_PENDING,
892*4882a593Smuzhiyun CI_UPDATE_NO_COALESC);
893*4882a593Smuzhiyun if (err)
894*4882a593Smuzhiyun goto err_hw_ci;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun err = tx_request_irq(txq);
897*4882a593Smuzhiyun if (err) {
898*4882a593Smuzhiyun netdev_err(netdev, "Failed to request Tx irq\n");
899*4882a593Smuzhiyun goto err_req_tx_irq;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun return 0;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun err_req_tx_irq:
905*4882a593Smuzhiyun err_hw_ci:
906*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->irq_name);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun err_alloc_irqname:
909*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->free_sges);
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun err_alloc_free_sges:
912*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->sges);
913*4882a593Smuzhiyun return err;
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun /**
917*4882a593Smuzhiyun * hinic_clean_txq - Clean the Tx Queue
918*4882a593Smuzhiyun * @txq: Logical Tx Queue
919*4882a593Smuzhiyun **/
hinic_clean_txq(struct hinic_txq * txq)920*4882a593Smuzhiyun void hinic_clean_txq(struct hinic_txq *txq)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun struct net_device *netdev = txq->netdev;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun tx_free_irq(txq);
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun free_all_tx_skbs(txq);
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->irq_name);
929*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->free_sges);
930*4882a593Smuzhiyun devm_kfree(&netdev->dev, txq->sges);
931*4882a593Smuzhiyun }
932