162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Huawei HiNIC PCI Express Linux driver
462306a36Sopenharmony_ci * Copyright(c) 2017 Huawei Technologies Co., Ltd
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/netdevice.h>
1362306a36Sopenharmony_ci#include <linux/etherdevice.h>
1462306a36Sopenharmony_ci#include <linux/u64_stats_sync.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/skbuff.h>
1862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1962306a36Sopenharmony_ci#include <linux/prefetch.h>
2062306a36Sopenharmony_ci#include <linux/cpumask.h>
2162306a36Sopenharmony_ci#include <linux/if_vlan.h>
2262306a36Sopenharmony_ci#include <asm/barrier.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "hinic_common.h"
2562306a36Sopenharmony_ci#include "hinic_hw_if.h"
2662306a36Sopenharmony_ci#include "hinic_hw_wqe.h"
2762306a36Sopenharmony_ci#include "hinic_hw_wq.h"
2862306a36Sopenharmony_ci#include "hinic_hw_qp.h"
2962306a36Sopenharmony_ci#include "hinic_hw_dev.h"
3062306a36Sopenharmony_ci#include "hinic_rx.h"
3162306a36Sopenharmony_ci#include "hinic_dev.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define RX_IRQ_NO_PENDING               0
3462306a36Sopenharmony_ci#define RX_IRQ_NO_COALESC               0
3562306a36Sopenharmony_ci#define RX_IRQ_NO_LLI_TIMER             0
3662306a36Sopenharmony_ci#define RX_IRQ_NO_CREDIT                0
3762306a36Sopenharmony_ci#define RX_IRQ_NO_RESEND_TIMER          0
3862306a36Sopenharmony_ci#define HINIC_RX_BUFFER_WRITE           16
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define HINIC_RX_IPV6_PKT		7
4162306a36Sopenharmony_ci#define LRO_PKT_HDR_LEN_IPV4		66
4262306a36Sopenharmony_ci#define LRO_PKT_HDR_LEN_IPV6		86
4362306a36Sopenharmony_ci#define LRO_REPLENISH_THLD		256
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define LRO_PKT_HDR_LEN(cqe)		\
4662306a36Sopenharmony_ci	(HINIC_GET_RX_PKT_TYPE(be32_to_cpu((cqe)->offload_type)) == \
4762306a36Sopenharmony_ci	 HINIC_RX_IPV6_PKT ? LRO_PKT_HDR_LEN_IPV6 : LRO_PKT_HDR_LEN_IPV4)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/**
5062306a36Sopenharmony_ci * hinic_rxq_clean_stats - Clean the statistics of specific queue
5162306a36Sopenharmony_ci * @rxq: Logical Rx Queue
5262306a36Sopenharmony_ci **/
5362306a36Sopenharmony_cistatic void hinic_rxq_clean_stats(struct hinic_rxq *rxq)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct hinic_rxq_stats *rxq_stats = &rxq->rxq_stats;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	u64_stats_update_begin(&rxq_stats->syncp);
5862306a36Sopenharmony_ci	rxq_stats->pkts  = 0;
5962306a36Sopenharmony_ci	rxq_stats->bytes = 0;
6062306a36Sopenharmony_ci	rxq_stats->errors = 0;
6162306a36Sopenharmony_ci	rxq_stats->csum_errors = 0;
6262306a36Sopenharmony_ci	rxq_stats->other_errors = 0;
6362306a36Sopenharmony_ci	u64_stats_update_end(&rxq_stats->syncp);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/**
6762306a36Sopenharmony_ci * hinic_rxq_get_stats - get statistics of Rx Queue
6862306a36Sopenharmony_ci * @rxq: Logical Rx Queue
6962306a36Sopenharmony_ci * @stats: return updated stats here
7062306a36Sopenharmony_ci **/
7162306a36Sopenharmony_civoid hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct hinic_rxq_stats *rxq_stats = &rxq->rxq_stats;
7462306a36Sopenharmony_ci	unsigned int start;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	do {
7762306a36Sopenharmony_ci		start = u64_stats_fetch_begin(&rxq_stats->syncp);
7862306a36Sopenharmony_ci		stats->pkts = rxq_stats->pkts;
7962306a36Sopenharmony_ci		stats->bytes = rxq_stats->bytes;
8062306a36Sopenharmony_ci		stats->errors = rxq_stats->csum_errors +
8162306a36Sopenharmony_ci				rxq_stats->other_errors;
8262306a36Sopenharmony_ci		stats->csum_errors = rxq_stats->csum_errors;
8362306a36Sopenharmony_ci		stats->other_errors = rxq_stats->other_errors;
8462306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/**
8862306a36Sopenharmony_ci * rxq_stats_init - Initialize the statistics of specific queue
8962306a36Sopenharmony_ci * @rxq: Logical Rx Queue
9062306a36Sopenharmony_ci **/
9162306a36Sopenharmony_cistatic void rxq_stats_init(struct hinic_rxq *rxq)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct hinic_rxq_stats *rxq_stats = &rxq->rxq_stats;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	u64_stats_init(&rxq_stats->syncp);
9662306a36Sopenharmony_ci	hinic_rxq_clean_stats(rxq);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic void rx_csum(struct hinic_rxq *rxq, u32 status,
10062306a36Sopenharmony_ci		    struct sk_buff *skb)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct net_device *netdev = rxq->netdev;
10362306a36Sopenharmony_ci	u32 csum_err;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	csum_err = HINIC_RQ_CQE_STATUS_GET(status, CSUM_ERR);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (!(netdev->features & NETIF_F_RXCSUM))
10862306a36Sopenharmony_ci		return;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!csum_err) {
11162306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
11262306a36Sopenharmony_ci	} else {
11362306a36Sopenharmony_ci		if (!(csum_err & (HINIC_RX_CSUM_HW_CHECK_NONE |
11462306a36Sopenharmony_ci			HINIC_RX_CSUM_IPSU_OTHER_ERR)))
11562306a36Sopenharmony_ci			rxq->rxq_stats.csum_errors++;
11662306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/**
12162306a36Sopenharmony_ci * rx_alloc_skb - allocate skb and map it to dma address
12262306a36Sopenharmony_ci * @rxq: rx queue
12362306a36Sopenharmony_ci * @dma_addr: returned dma address for the skb
12462306a36Sopenharmony_ci *
12562306a36Sopenharmony_ci * Return skb
12662306a36Sopenharmony_ci **/
12762306a36Sopenharmony_cistatic struct sk_buff *rx_alloc_skb(struct hinic_rxq *rxq,
12862306a36Sopenharmony_ci				    dma_addr_t *dma_addr)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
13162306a36Sopenharmony_ci	struct hinic_hwdev *hwdev = nic_dev->hwdev;
13262306a36Sopenharmony_ci	struct hinic_hwif *hwif = hwdev->hwif;
13362306a36Sopenharmony_ci	struct pci_dev *pdev = hwif->pdev;
13462306a36Sopenharmony_ci	struct sk_buff *skb;
13562306a36Sopenharmony_ci	dma_addr_t addr;
13662306a36Sopenharmony_ci	int err;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	skb = netdev_alloc_skb_ip_align(rxq->netdev, rxq->rq->buf_sz);
13962306a36Sopenharmony_ci	if (!skb)
14062306a36Sopenharmony_ci		return NULL;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	addr = dma_map_single(&pdev->dev, skb->data, rxq->rq->buf_sz,
14362306a36Sopenharmony_ci			      DMA_FROM_DEVICE);
14462306a36Sopenharmony_ci	err = dma_mapping_error(&pdev->dev, addr);
14562306a36Sopenharmony_ci	if (err) {
14662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to map Rx DMA, err = %d\n", err);
14762306a36Sopenharmony_ci		goto err_rx_map;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	*dma_addr = addr;
15162306a36Sopenharmony_ci	return skb;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cierr_rx_map:
15462306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
15562306a36Sopenharmony_ci	return NULL;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/**
15962306a36Sopenharmony_ci * rx_unmap_skb - unmap the dma address of the skb
16062306a36Sopenharmony_ci * @rxq: rx queue
16162306a36Sopenharmony_ci * @dma_addr: dma address of the skb
16262306a36Sopenharmony_ci **/
16362306a36Sopenharmony_cistatic void rx_unmap_skb(struct hinic_rxq *rxq, dma_addr_t dma_addr)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
16662306a36Sopenharmony_ci	struct hinic_hwdev *hwdev = nic_dev->hwdev;
16762306a36Sopenharmony_ci	struct hinic_hwif *hwif = hwdev->hwif;
16862306a36Sopenharmony_ci	struct pci_dev *pdev = hwif->pdev;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	dma_unmap_single(&pdev->dev, dma_addr, rxq->rq->buf_sz,
17162306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * rx_free_skb - unmap and free skb
17662306a36Sopenharmony_ci * @rxq: rx queue
17762306a36Sopenharmony_ci * @skb: skb to free
17862306a36Sopenharmony_ci * @dma_addr: dma address of the skb
17962306a36Sopenharmony_ci **/
18062306a36Sopenharmony_cistatic void rx_free_skb(struct hinic_rxq *rxq, struct sk_buff *skb,
18162306a36Sopenharmony_ci			dma_addr_t dma_addr)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	rx_unmap_skb(rxq, dma_addr);
18462306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/**
18862306a36Sopenharmony_ci * rx_alloc_pkts - allocate pkts in rx queue
18962306a36Sopenharmony_ci * @rxq: rx queue
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * Return number of skbs allocated
19262306a36Sopenharmony_ci **/
19362306a36Sopenharmony_cistatic int rx_alloc_pkts(struct hinic_rxq *rxq)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
19662306a36Sopenharmony_ci	struct hinic_rq_wqe *rq_wqe;
19762306a36Sopenharmony_ci	unsigned int free_wqebbs;
19862306a36Sopenharmony_ci	struct hinic_sge sge;
19962306a36Sopenharmony_ci	dma_addr_t dma_addr;
20062306a36Sopenharmony_ci	struct sk_buff *skb;
20162306a36Sopenharmony_ci	u16 prod_idx;
20262306a36Sopenharmony_ci	int i;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	free_wqebbs = hinic_get_rq_free_wqebbs(rxq->rq);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Limit the allocation chunks */
20762306a36Sopenharmony_ci	if (free_wqebbs > nic_dev->rx_weight)
20862306a36Sopenharmony_ci		free_wqebbs = nic_dev->rx_weight;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	for (i = 0; i < free_wqebbs; i++) {
21162306a36Sopenharmony_ci		skb = rx_alloc_skb(rxq, &dma_addr);
21262306a36Sopenharmony_ci		if (!skb)
21362306a36Sopenharmony_ci			goto skb_out;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		hinic_set_sge(&sge, dma_addr, skb->len);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		rq_wqe = hinic_rq_get_wqe(rxq->rq, HINIC_RQ_WQE_SIZE,
21862306a36Sopenharmony_ci					  &prod_idx);
21962306a36Sopenharmony_ci		if (!rq_wqe) {
22062306a36Sopenharmony_ci			rx_free_skb(rxq, skb, dma_addr);
22162306a36Sopenharmony_ci			goto skb_out;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		hinic_rq_prepare_wqe(rxq->rq, prod_idx, rq_wqe, &sge);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		hinic_rq_write_wqe(rxq->rq, prod_idx, rq_wqe, skb);
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ciskb_out:
23062306a36Sopenharmony_ci	if (i) {
23162306a36Sopenharmony_ci		wmb();  /* write all the wqes before update PI */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		hinic_rq_update(rxq->rq, prod_idx);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return i;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * free_all_rx_skbs - free all skbs in rx queue
24162306a36Sopenharmony_ci * @rxq: rx queue
24262306a36Sopenharmony_ci **/
24362306a36Sopenharmony_cistatic void free_all_rx_skbs(struct hinic_rxq *rxq)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
24662306a36Sopenharmony_ci	struct hinic_hw_wqe *hw_wqe;
24762306a36Sopenharmony_ci	struct hinic_sge sge;
24862306a36Sopenharmony_ci	u16 ci;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	while ((hw_wqe = hinic_read_wqe(rq->wq, HINIC_RQ_WQE_SIZE, &ci))) {
25162306a36Sopenharmony_ci		if (IS_ERR(hw_wqe))
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		hinic_rq_get_sge(rq, &hw_wqe->rq_wqe, ci, &sge);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		hinic_put_wqe(rq->wq, HINIC_RQ_WQE_SIZE);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		rx_free_skb(rxq, rq->saved_skb[ci], hinic_sge_to_dma(&sge));
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * rx_recv_jumbo_pkt - Rx handler for jumbo pkt
26462306a36Sopenharmony_ci * @rxq: rx queue
26562306a36Sopenharmony_ci * @head_skb: the first skb in the list
26662306a36Sopenharmony_ci * @left_pkt_len: left size of the pkt exclude head skb
26762306a36Sopenharmony_ci * @ci: consumer index
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci * Return number of wqes that used for the left of the pkt
27062306a36Sopenharmony_ci **/
27162306a36Sopenharmony_cistatic int rx_recv_jumbo_pkt(struct hinic_rxq *rxq, struct sk_buff *head_skb,
27262306a36Sopenharmony_ci			     unsigned int left_pkt_len, u16 ci)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct sk_buff *skb, *curr_skb = head_skb;
27562306a36Sopenharmony_ci	struct hinic_rq_wqe *rq_wqe;
27662306a36Sopenharmony_ci	unsigned int curr_len;
27762306a36Sopenharmony_ci	struct hinic_sge sge;
27862306a36Sopenharmony_ci	int num_wqes = 0;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	while (left_pkt_len > 0) {
28162306a36Sopenharmony_ci		rq_wqe = hinic_rq_read_next_wqe(rxq->rq, HINIC_RQ_WQE_SIZE,
28262306a36Sopenharmony_ci						&skb, &ci);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		num_wqes++;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		hinic_rq_get_sge(rxq->rq, rq_wqe, ci, &sge);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		rx_unmap_skb(rxq, hinic_sge_to_dma(&sge));
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		prefetch(skb->data);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		curr_len = (left_pkt_len > HINIC_RX_BUF_SZ) ? HINIC_RX_BUF_SZ :
29362306a36Sopenharmony_ci			    left_pkt_len;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		left_pkt_len -= curr_len;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		__skb_put(skb, curr_len);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		if (curr_skb == head_skb)
30062306a36Sopenharmony_ci			skb_shinfo(head_skb)->frag_list = skb;
30162306a36Sopenharmony_ci		else
30262306a36Sopenharmony_ci			curr_skb->next = skb;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		head_skb->len += skb->len;
30562306a36Sopenharmony_ci		head_skb->data_len += skb->len;
30662306a36Sopenharmony_ci		head_skb->truesize += skb->truesize;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		curr_skb = skb;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return num_wqes;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void hinic_copy_lp_data(struct hinic_dev *nic_dev,
31562306a36Sopenharmony_ci			       struct sk_buff *skb)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct net_device *netdev = nic_dev->netdev;
31862306a36Sopenharmony_ci	u8 *lb_buf = nic_dev->lb_test_rx_buf;
31962306a36Sopenharmony_ci	int lb_len = nic_dev->lb_pkt_len;
32062306a36Sopenharmony_ci	int pkt_offset, frag_len, i;
32162306a36Sopenharmony_ci	void *frag_data = NULL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (nic_dev->lb_test_rx_idx == LP_PKT_CNT) {
32462306a36Sopenharmony_ci		nic_dev->lb_test_rx_idx = 0;
32562306a36Sopenharmony_ci		netif_warn(nic_dev, drv, netdev, "Loopback test warning, receive too more test pkts\n");
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (skb->len != nic_dev->lb_pkt_len) {
32962306a36Sopenharmony_ci		netif_warn(nic_dev, drv, netdev, "Wrong packet length\n");
33062306a36Sopenharmony_ci		nic_dev->lb_test_rx_idx++;
33162306a36Sopenharmony_ci		return;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	pkt_offset = nic_dev->lb_test_rx_idx * lb_len;
33562306a36Sopenharmony_ci	frag_len = (int)skb_headlen(skb);
33662306a36Sopenharmony_ci	memcpy(lb_buf + pkt_offset, skb->data, frag_len);
33762306a36Sopenharmony_ci	pkt_offset += frag_len;
33862306a36Sopenharmony_ci	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
33962306a36Sopenharmony_ci		frag_data = skb_frag_address(&skb_shinfo(skb)->frags[i]);
34062306a36Sopenharmony_ci		frag_len = (int)skb_frag_size(&skb_shinfo(skb)->frags[i]);
34162306a36Sopenharmony_ci		memcpy((lb_buf + pkt_offset), frag_data, frag_len);
34262306a36Sopenharmony_ci		pkt_offset += frag_len;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	nic_dev->lb_test_rx_idx++;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/**
34862306a36Sopenharmony_ci * rxq_recv - Rx handler
34962306a36Sopenharmony_ci * @rxq: rx queue
35062306a36Sopenharmony_ci * @budget: maximum pkts to process
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * Return number of pkts received
35362306a36Sopenharmony_ci **/
35462306a36Sopenharmony_cistatic int rxq_recv(struct hinic_rxq *rxq, int budget)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct hinic_qp *qp = container_of(rxq->rq, struct hinic_qp, rq);
35762306a36Sopenharmony_ci	struct net_device *netdev = rxq->netdev;
35862306a36Sopenharmony_ci	u64 pkt_len = 0, rx_bytes = 0;
35962306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
36062306a36Sopenharmony_ci	struct hinic_rq_wqe *rq_wqe;
36162306a36Sopenharmony_ci	struct hinic_dev *nic_dev;
36262306a36Sopenharmony_ci	unsigned int free_wqebbs;
36362306a36Sopenharmony_ci	struct hinic_rq_cqe *cqe;
36462306a36Sopenharmony_ci	int num_wqes, pkts = 0;
36562306a36Sopenharmony_ci	struct hinic_sge sge;
36662306a36Sopenharmony_ci	unsigned int status;
36762306a36Sopenharmony_ci	struct sk_buff *skb;
36862306a36Sopenharmony_ci	u32 offload_type;
36962306a36Sopenharmony_ci	u16 ci, num_lro;
37062306a36Sopenharmony_ci	u16 num_wqe = 0;
37162306a36Sopenharmony_ci	u32 vlan_len;
37262306a36Sopenharmony_ci	u16 vid;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	nic_dev = netdev_priv(netdev);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	while (pkts < budget) {
37762306a36Sopenharmony_ci		num_wqes = 0;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		rq_wqe = hinic_rq_read_wqe(rxq->rq, HINIC_RQ_WQE_SIZE, &skb,
38062306a36Sopenharmony_ci					   &ci);
38162306a36Sopenharmony_ci		if (!rq_wqe)
38262306a36Sopenharmony_ci			break;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		/* make sure we read rx_done before packet length */
38562306a36Sopenharmony_ci		dma_rmb();
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		cqe = rq->cqe[ci];
38862306a36Sopenharmony_ci		status =  be32_to_cpu(cqe->status);
38962306a36Sopenharmony_ci		hinic_rq_get_sge(rxq->rq, rq_wqe, ci, &sge);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		rx_unmap_skb(rxq, hinic_sge_to_dma(&sge));
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		rx_csum(rxq, status, skb);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		prefetch(skb->data);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		pkt_len = sge.len;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci		if (pkt_len <= HINIC_RX_BUF_SZ) {
40062306a36Sopenharmony_ci			__skb_put(skb, pkt_len);
40162306a36Sopenharmony_ci		} else {
40262306a36Sopenharmony_ci			__skb_put(skb, HINIC_RX_BUF_SZ);
40362306a36Sopenharmony_ci			num_wqes = rx_recv_jumbo_pkt(rxq, skb, pkt_len -
40462306a36Sopenharmony_ci						     HINIC_RX_BUF_SZ, ci);
40562306a36Sopenharmony_ci		}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		hinic_rq_put_wqe(rq, ci,
40862306a36Sopenharmony_ci				 (num_wqes + 1) * HINIC_RQ_WQE_SIZE);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		offload_type = be32_to_cpu(cqe->offload_type);
41162306a36Sopenharmony_ci		vlan_len = be32_to_cpu(cqe->len);
41262306a36Sopenharmony_ci		if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
41362306a36Sopenharmony_ci		    HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)) {
41462306a36Sopenharmony_ci			vid = HINIC_GET_RX_VLAN_TAG(vlan_len);
41562306a36Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		if (unlikely(nic_dev->flags & HINIC_LP_TEST))
41962306a36Sopenharmony_ci			hinic_copy_lp_data(nic_dev, skb);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		skb_record_rx_queue(skb, qp->q_id);
42262306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, rxq->netdev);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		napi_gro_receive(&rxq->napi, skb);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		pkts++;
42762306a36Sopenharmony_ci		rx_bytes += pkt_len;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		num_lro = HINIC_GET_RX_NUM_LRO(status);
43062306a36Sopenharmony_ci		if (num_lro) {
43162306a36Sopenharmony_ci			rx_bytes += ((num_lro - 1) *
43262306a36Sopenharmony_ci				     LRO_PKT_HDR_LEN(cqe));
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci			num_wqe +=
43562306a36Sopenharmony_ci			(u16)(pkt_len >> rxq->rx_buff_shift) +
43662306a36Sopenharmony_ci			((pkt_len & (rxq->buf_len - 1)) ? 1 : 0);
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		cqe->status = 0;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		if (num_wqe >= LRO_REPLENISH_THLD)
44262306a36Sopenharmony_ci			break;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	free_wqebbs = hinic_get_rq_free_wqebbs(rxq->rq);
44662306a36Sopenharmony_ci	if (free_wqebbs > HINIC_RX_BUFFER_WRITE)
44762306a36Sopenharmony_ci		rx_alloc_pkts(rxq);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	u64_stats_update_begin(&rxq->rxq_stats.syncp);
45062306a36Sopenharmony_ci	rxq->rxq_stats.pkts += pkts;
45162306a36Sopenharmony_ci	rxq->rxq_stats.bytes += rx_bytes;
45262306a36Sopenharmony_ci	u64_stats_update_end(&rxq->rxq_stats.syncp);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return pkts;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int rx_poll(struct napi_struct *napi, int budget)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct hinic_rxq *rxq = container_of(napi, struct hinic_rxq, napi);
46062306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
46162306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
46262306a36Sopenharmony_ci	int pkts;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	pkts = rxq_recv(rxq, budget);
46562306a36Sopenharmony_ci	if (pkts >= budget)
46662306a36Sopenharmony_ci		return budget;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	napi_complete(napi);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
47162306a36Sopenharmony_ci		hinic_hwdev_set_msix_state(nic_dev->hwdev,
47262306a36Sopenharmony_ci					   rq->msix_entry,
47362306a36Sopenharmony_ci					   HINIC_MSIX_ENABLE);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return pkts;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void rx_add_napi(struct hinic_rxq *rxq)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	netif_napi_add_weight(rxq->netdev, &rxq->napi, rx_poll,
48362306a36Sopenharmony_ci			      nic_dev->rx_weight);
48462306a36Sopenharmony_ci	napi_enable(&rxq->napi);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic void rx_del_napi(struct hinic_rxq *rxq)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	napi_disable(&rxq->napi);
49062306a36Sopenharmony_ci	netif_napi_del(&rxq->napi);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic irqreturn_t rx_irq(int irq, void *data)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct hinic_rxq *rxq = (struct hinic_rxq *)data;
49662306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
49762306a36Sopenharmony_ci	struct hinic_dev *nic_dev;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* Disable the interrupt until napi will be completed */
50062306a36Sopenharmony_ci	nic_dev = netdev_priv(rxq->netdev);
50162306a36Sopenharmony_ci	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
50262306a36Sopenharmony_ci		hinic_hwdev_set_msix_state(nic_dev->hwdev,
50362306a36Sopenharmony_ci					   rq->msix_entry,
50462306a36Sopenharmony_ci					   HINIC_MSIX_DISABLE);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	nic_dev = netdev_priv(rxq->netdev);
50762306a36Sopenharmony_ci	hinic_hwdev_msix_cnt_set(nic_dev->hwdev, rq->msix_entry);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	napi_schedule(&rxq->napi);
51062306a36Sopenharmony_ci	return IRQ_HANDLED;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int rx_request_irq(struct hinic_rxq *rxq)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct hinic_dev *nic_dev = netdev_priv(rxq->netdev);
51662306a36Sopenharmony_ci	struct hinic_msix_config interrupt_info = {0};
51762306a36Sopenharmony_ci	struct hinic_intr_coal_info *intr_coal = NULL;
51862306a36Sopenharmony_ci	struct hinic_hwdev *hwdev = nic_dev->hwdev;
51962306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
52062306a36Sopenharmony_ci	struct hinic_qp *qp;
52162306a36Sopenharmony_ci	int err;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	qp = container_of(rq, struct hinic_qp, rq);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	rx_add_napi(rxq);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	hinic_hwdev_msix_set(hwdev, rq->msix_entry,
52862306a36Sopenharmony_ci			     RX_IRQ_NO_PENDING, RX_IRQ_NO_COALESC,
52962306a36Sopenharmony_ci			     RX_IRQ_NO_LLI_TIMER, RX_IRQ_NO_CREDIT,
53062306a36Sopenharmony_ci			     RX_IRQ_NO_RESEND_TIMER);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	intr_coal = &nic_dev->rx_intr_coalesce[qp->q_id];
53362306a36Sopenharmony_ci	interrupt_info.msix_index = rq->msix_entry;
53462306a36Sopenharmony_ci	interrupt_info.coalesce_timer_cnt = intr_coal->coalesce_timer_cfg;
53562306a36Sopenharmony_ci	interrupt_info.pending_cnt = intr_coal->pending_limt;
53662306a36Sopenharmony_ci	interrupt_info.resend_timer_cnt = intr_coal->resend_timer_cfg;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	err = hinic_set_interrupt_cfg(hwdev, &interrupt_info);
53962306a36Sopenharmony_ci	if (err) {
54062306a36Sopenharmony_ci		netif_err(nic_dev, drv, rxq->netdev,
54162306a36Sopenharmony_ci			  "Failed to set RX interrupt coalescing attribute\n");
54262306a36Sopenharmony_ci		goto err_req_irq;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	err = request_irq(rq->irq, rx_irq, 0, rxq->irq_name, rxq);
54662306a36Sopenharmony_ci	if (err)
54762306a36Sopenharmony_ci		goto err_req_irq;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
55062306a36Sopenharmony_ci	err = irq_set_affinity_and_hint(rq->irq, &rq->affinity_mask);
55162306a36Sopenharmony_ci	if (err)
55262306a36Sopenharmony_ci		goto err_irq_affinity;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cierr_irq_affinity:
55762306a36Sopenharmony_ci	free_irq(rq->irq, rxq);
55862306a36Sopenharmony_cierr_req_irq:
55962306a36Sopenharmony_ci	rx_del_napi(rxq);
56062306a36Sopenharmony_ci	return err;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic void rx_free_irq(struct hinic_rxq *rxq)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct hinic_rq *rq = rxq->rq;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	irq_update_affinity_hint(rq->irq, NULL);
56862306a36Sopenharmony_ci	free_irq(rq->irq, rxq);
56962306a36Sopenharmony_ci	rx_del_napi(rxq);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci/**
57362306a36Sopenharmony_ci * hinic_init_rxq - Initialize the Rx Queue
57462306a36Sopenharmony_ci * @rxq: Logical Rx Queue
57562306a36Sopenharmony_ci * @rq: Hardware Rx Queue to connect the Logical queue with
57662306a36Sopenharmony_ci * @netdev: network device to connect the Logical queue with
57762306a36Sopenharmony_ci *
57862306a36Sopenharmony_ci * Return 0 - Success, negative - Failure
57962306a36Sopenharmony_ci **/
58062306a36Sopenharmony_ciint hinic_init_rxq(struct hinic_rxq *rxq, struct hinic_rq *rq,
58162306a36Sopenharmony_ci		   struct net_device *netdev)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct hinic_qp *qp = container_of(rq, struct hinic_qp, rq);
58462306a36Sopenharmony_ci	int err, pkts;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	rxq->netdev = netdev;
58762306a36Sopenharmony_ci	rxq->rq = rq;
58862306a36Sopenharmony_ci	rxq->buf_len = HINIC_RX_BUF_SZ;
58962306a36Sopenharmony_ci	rxq->rx_buff_shift = ilog2(HINIC_RX_BUF_SZ);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	rxq_stats_init(rxq);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	rxq->irq_name = devm_kasprintf(&netdev->dev, GFP_KERNEL,
59462306a36Sopenharmony_ci				       "%s_rxq%d", netdev->name, qp->q_id);
59562306a36Sopenharmony_ci	if (!rxq->irq_name)
59662306a36Sopenharmony_ci		return -ENOMEM;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	pkts = rx_alloc_pkts(rxq);
59962306a36Sopenharmony_ci	if (!pkts) {
60062306a36Sopenharmony_ci		err = -ENOMEM;
60162306a36Sopenharmony_ci		goto err_rx_pkts;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	err = rx_request_irq(rxq);
60562306a36Sopenharmony_ci	if (err) {
60662306a36Sopenharmony_ci		netdev_err(netdev, "Failed to request Rx irq\n");
60762306a36Sopenharmony_ci		goto err_req_rx_irq;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	return 0;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cierr_req_rx_irq:
61362306a36Sopenharmony_cierr_rx_pkts:
61462306a36Sopenharmony_ci	free_all_rx_skbs(rxq);
61562306a36Sopenharmony_ci	devm_kfree(&netdev->dev, rxq->irq_name);
61662306a36Sopenharmony_ci	return err;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/**
62062306a36Sopenharmony_ci * hinic_clean_rxq - Clean the Rx Queue
62162306a36Sopenharmony_ci * @rxq: Logical Rx Queue
62262306a36Sopenharmony_ci **/
62362306a36Sopenharmony_civoid hinic_clean_rxq(struct hinic_rxq *rxq)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct net_device *netdev = rxq->netdev;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	rx_free_irq(rxq);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	free_all_rx_skbs(rxq);
63062306a36Sopenharmony_ci	devm_kfree(&netdev->dev, rxq->irq_name);
63162306a36Sopenharmony_ci}
632