18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Atlantic Network Driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation
58c2ecf20Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/* File aq_ring.c: Definition of functions for Rx/Tx rings. */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "aq_ring.h"
118c2ecf20Sopenharmony_ci#include "aq_nic.h"
128c2ecf20Sopenharmony_ci#include "aq_hw.h"
138c2ecf20Sopenharmony_ci#include "aq_hw_utils.h"
148c2ecf20Sopenharmony_ci#include "aq_ptp.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic inline void aq_free_rxpage(struct aq_rxpage *rxpage, struct device *dev)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	unsigned int len = PAGE_SIZE << rxpage->order;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	dma_unmap_page(dev, rxpage->daddr, len, DMA_FROM_DEVICE);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	/* Drop the ref for being in the ring. */
268c2ecf20Sopenharmony_ci	__free_pages(rxpage->page, rxpage->order);
278c2ecf20Sopenharmony_ci	rxpage->page = NULL;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int aq_get_rxpage(struct aq_rxpage *rxpage, unsigned int order,
318c2ecf20Sopenharmony_ci			 struct device *dev)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct page *page;
348c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
358c2ecf20Sopenharmony_ci	dma_addr_t daddr;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	page = dev_alloc_pages(order);
388c2ecf20Sopenharmony_ci	if (unlikely(!page))
398c2ecf20Sopenharmony_ci		goto err_exit;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	daddr = dma_map_page(dev, page, 0, PAGE_SIZE << order,
428c2ecf20Sopenharmony_ci			     DMA_FROM_DEVICE);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(dev, daddr)))
458c2ecf20Sopenharmony_ci		goto free_page;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	rxpage->page = page;
488c2ecf20Sopenharmony_ci	rxpage->daddr = daddr;
498c2ecf20Sopenharmony_ci	rxpage->order = order;
508c2ecf20Sopenharmony_ci	rxpage->pg_off = 0;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return 0;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cifree_page:
558c2ecf20Sopenharmony_ci	__free_pages(page, order);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cierr_exit:
588c2ecf20Sopenharmony_ci	return ret;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int aq_get_rxpages(struct aq_ring_s *self, struct aq_ring_buff_s *rxbuf,
628c2ecf20Sopenharmony_ci			  int order)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	int ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (rxbuf->rxdata.page) {
678c2ecf20Sopenharmony_ci		/* One means ring is the only user and can reuse */
688c2ecf20Sopenharmony_ci		if (page_ref_count(rxbuf->rxdata.page) > 1) {
698c2ecf20Sopenharmony_ci			/* Try reuse buffer */
708c2ecf20Sopenharmony_ci			rxbuf->rxdata.pg_off += AQ_CFG_RX_FRAME_MAX;
718c2ecf20Sopenharmony_ci			if (rxbuf->rxdata.pg_off + AQ_CFG_RX_FRAME_MAX <=
728c2ecf20Sopenharmony_ci				(PAGE_SIZE << order)) {
738c2ecf20Sopenharmony_ci				u64_stats_update_begin(&self->stats.rx.syncp);
748c2ecf20Sopenharmony_ci				self->stats.rx.pg_flips++;
758c2ecf20Sopenharmony_ci				u64_stats_update_end(&self->stats.rx.syncp);
768c2ecf20Sopenharmony_ci			} else {
778c2ecf20Sopenharmony_ci				/* Buffer exhausted. We have other users and
788c2ecf20Sopenharmony_ci				 * should release this page and realloc
798c2ecf20Sopenharmony_ci				 */
808c2ecf20Sopenharmony_ci				aq_free_rxpage(&rxbuf->rxdata,
818c2ecf20Sopenharmony_ci					       aq_nic_get_dev(self->aq_nic));
828c2ecf20Sopenharmony_ci				u64_stats_update_begin(&self->stats.rx.syncp);
838c2ecf20Sopenharmony_ci				self->stats.rx.pg_losts++;
848c2ecf20Sopenharmony_ci				u64_stats_update_end(&self->stats.rx.syncp);
858c2ecf20Sopenharmony_ci			}
868c2ecf20Sopenharmony_ci		} else {
878c2ecf20Sopenharmony_ci			rxbuf->rxdata.pg_off = 0;
888c2ecf20Sopenharmony_ci			u64_stats_update_begin(&self->stats.rx.syncp);
898c2ecf20Sopenharmony_ci			self->stats.rx.pg_reuses++;
908c2ecf20Sopenharmony_ci			u64_stats_update_end(&self->stats.rx.syncp);
918c2ecf20Sopenharmony_ci		}
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (!rxbuf->rxdata.page) {
958c2ecf20Sopenharmony_ci		ret = aq_get_rxpage(&rxbuf->rxdata, order,
968c2ecf20Sopenharmony_ci				    aq_nic_get_dev(self->aq_nic));
978c2ecf20Sopenharmony_ci		if (ret) {
988c2ecf20Sopenharmony_ci			u64_stats_update_begin(&self->stats.rx.syncp);
998c2ecf20Sopenharmony_ci			self->stats.rx.alloc_fails++;
1008c2ecf20Sopenharmony_ci			u64_stats_update_end(&self->stats.rx.syncp);
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci		return ret;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
1098c2ecf20Sopenharmony_ci				       struct aq_nic_s *aq_nic)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int err = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	self->buff_ring =
1148c2ecf20Sopenharmony_ci		kcalloc(self->size, sizeof(struct aq_ring_buff_s), GFP_KERNEL);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (!self->buff_ring) {
1178c2ecf20Sopenharmony_ci		err = -ENOMEM;
1188c2ecf20Sopenharmony_ci		goto err_exit;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci	self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic),
1218c2ecf20Sopenharmony_ci					   self->size * self->dx_size,
1228c2ecf20Sopenharmony_ci					   &self->dx_ring_pa, GFP_KERNEL);
1238c2ecf20Sopenharmony_ci	if (!self->dx_ring) {
1248c2ecf20Sopenharmony_ci		err = -ENOMEM;
1258c2ecf20Sopenharmony_ci		goto err_exit;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cierr_exit:
1298c2ecf20Sopenharmony_ci	if (err < 0) {
1308c2ecf20Sopenharmony_ci		aq_ring_free(self);
1318c2ecf20Sopenharmony_ci		self = NULL;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return self;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistruct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
1388c2ecf20Sopenharmony_ci				   struct aq_nic_s *aq_nic,
1398c2ecf20Sopenharmony_ci				   unsigned int idx,
1408c2ecf20Sopenharmony_ci				   struct aq_nic_cfg_s *aq_nic_cfg)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	int err = 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	self->aq_nic = aq_nic;
1458c2ecf20Sopenharmony_ci	self->idx = idx;
1468c2ecf20Sopenharmony_ci	self->size = aq_nic_cfg->txds;
1478c2ecf20Sopenharmony_ci	self->dx_size = aq_nic_cfg->aq_hw_caps->txd_size;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	self = aq_ring_alloc(self, aq_nic);
1508c2ecf20Sopenharmony_ci	if (!self) {
1518c2ecf20Sopenharmony_ci		err = -ENOMEM;
1528c2ecf20Sopenharmony_ci		goto err_exit;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cierr_exit:
1568c2ecf20Sopenharmony_ci	if (err < 0) {
1578c2ecf20Sopenharmony_ci		aq_ring_free(self);
1588c2ecf20Sopenharmony_ci		self = NULL;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return self;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistruct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
1658c2ecf20Sopenharmony_ci				   struct aq_nic_s *aq_nic,
1668c2ecf20Sopenharmony_ci				   unsigned int idx,
1678c2ecf20Sopenharmony_ci				   struct aq_nic_cfg_s *aq_nic_cfg)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int err = 0;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	self->aq_nic = aq_nic;
1728c2ecf20Sopenharmony_ci	self->idx = idx;
1738c2ecf20Sopenharmony_ci	self->size = aq_nic_cfg->rxds;
1748c2ecf20Sopenharmony_ci	self->dx_size = aq_nic_cfg->aq_hw_caps->rxd_size;
1758c2ecf20Sopenharmony_ci	self->page_order = fls(AQ_CFG_RX_FRAME_MAX / PAGE_SIZE +
1768c2ecf20Sopenharmony_ci			       (AQ_CFG_RX_FRAME_MAX % PAGE_SIZE ? 1 : 0)) - 1;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (aq_nic_cfg->rxpageorder > self->page_order)
1798c2ecf20Sopenharmony_ci		self->page_order = aq_nic_cfg->rxpageorder;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	self = aq_ring_alloc(self, aq_nic);
1828c2ecf20Sopenharmony_ci	if (!self) {
1838c2ecf20Sopenharmony_ci		err = -ENOMEM;
1848c2ecf20Sopenharmony_ci		goto err_exit;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cierr_exit:
1888c2ecf20Sopenharmony_ci	if (err < 0) {
1898c2ecf20Sopenharmony_ci		aq_ring_free(self);
1908c2ecf20Sopenharmony_ci		self = NULL;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return self;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistruct aq_ring_s *
1978c2ecf20Sopenharmony_ciaq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
1988c2ecf20Sopenharmony_ci		      unsigned int idx, unsigned int size, unsigned int dx_size)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct device *dev = aq_nic_get_dev(aq_nic);
2018c2ecf20Sopenharmony_ci	size_t sz = size * dx_size + AQ_CFG_RXDS_DEF;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	memset(self, 0, sizeof(*self));
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	self->aq_nic = aq_nic;
2068c2ecf20Sopenharmony_ci	self->idx = idx;
2078c2ecf20Sopenharmony_ci	self->size = size;
2088c2ecf20Sopenharmony_ci	self->dx_size = dx_size;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa,
2118c2ecf20Sopenharmony_ci					   GFP_KERNEL);
2128c2ecf20Sopenharmony_ci	if (!self->dx_ring) {
2138c2ecf20Sopenharmony_ci		aq_ring_free(self);
2148c2ecf20Sopenharmony_ci		return NULL;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return self;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciint aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	self->hw_head = 0;
2238c2ecf20Sopenharmony_ci	self->sw_head = 0;
2248c2ecf20Sopenharmony_ci	self->sw_tail = 0;
2258c2ecf20Sopenharmony_ci	self->ring_type = ring_type;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (self->ring_type == ATL_RING_RX)
2288c2ecf20Sopenharmony_ci		u64_stats_init(&self->stats.rx.syncp);
2298c2ecf20Sopenharmony_ci	else
2308c2ecf20Sopenharmony_ci		u64_stats_init(&self->stats.tx.syncp);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic inline bool aq_ring_dx_in_range(unsigned int h, unsigned int i,
2368c2ecf20Sopenharmony_ci				       unsigned int t)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	return (h < t) ? ((h < i) && (i < t)) : ((h < i) || (i < t));
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_civoid aq_ring_update_queue_state(struct aq_ring_s *ring)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	if (aq_ring_avail_dx(ring) <= AQ_CFG_SKB_FRAGS_MAX)
2448c2ecf20Sopenharmony_ci		aq_ring_queue_stop(ring);
2458c2ecf20Sopenharmony_ci	else if (aq_ring_avail_dx(ring) > AQ_CFG_RESTART_DESC_THRES)
2468c2ecf20Sopenharmony_ci		aq_ring_queue_wake(ring);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_civoid aq_ring_queue_wake(struct aq_ring_s *ring)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct net_device *ndev = aq_nic_get_ndev(ring->aq_nic);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (__netif_subqueue_stopped(ndev,
2548c2ecf20Sopenharmony_ci				     AQ_NIC_RING2QMAP(ring->aq_nic,
2558c2ecf20Sopenharmony_ci						      ring->idx))) {
2568c2ecf20Sopenharmony_ci		netif_wake_subqueue(ndev,
2578c2ecf20Sopenharmony_ci				    AQ_NIC_RING2QMAP(ring->aq_nic, ring->idx));
2588c2ecf20Sopenharmony_ci		u64_stats_update_begin(&ring->stats.tx.syncp);
2598c2ecf20Sopenharmony_ci		ring->stats.tx.queue_restarts++;
2608c2ecf20Sopenharmony_ci		u64_stats_update_end(&ring->stats.tx.syncp);
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_civoid aq_ring_queue_stop(struct aq_ring_s *ring)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct net_device *ndev = aq_nic_get_ndev(ring->aq_nic);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (!__netif_subqueue_stopped(ndev,
2698c2ecf20Sopenharmony_ci				      AQ_NIC_RING2QMAP(ring->aq_nic,
2708c2ecf20Sopenharmony_ci						       ring->idx)))
2718c2ecf20Sopenharmony_ci		netif_stop_subqueue(ndev,
2728c2ecf20Sopenharmony_ci				    AQ_NIC_RING2QMAP(ring->aq_nic, ring->idx));
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cibool aq_ring_tx_clean(struct aq_ring_s *self)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct device *dev = aq_nic_get_dev(self->aq_nic);
2788c2ecf20Sopenharmony_ci	unsigned int budget;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	for (budget = AQ_CFG_TX_CLEAN_BUDGET;
2818c2ecf20Sopenharmony_ci	     budget && self->sw_head != self->hw_head; budget--) {
2828c2ecf20Sopenharmony_ci		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		if (likely(buff->is_mapped)) {
2858c2ecf20Sopenharmony_ci			if (unlikely(buff->is_sop)) {
2868c2ecf20Sopenharmony_ci				if (!buff->is_eop &&
2878c2ecf20Sopenharmony_ci				    buff->eop_index != 0xffffU &&
2888c2ecf20Sopenharmony_ci				    (!aq_ring_dx_in_range(self->sw_head,
2898c2ecf20Sopenharmony_ci						buff->eop_index,
2908c2ecf20Sopenharmony_ci						self->hw_head)))
2918c2ecf20Sopenharmony_ci					break;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci				dma_unmap_single(dev, buff->pa, buff->len,
2948c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
2958c2ecf20Sopenharmony_ci			} else {
2968c2ecf20Sopenharmony_ci				dma_unmap_page(dev, buff->pa, buff->len,
2978c2ecf20Sopenharmony_ci					       DMA_TO_DEVICE);
2988c2ecf20Sopenharmony_ci			}
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		if (unlikely(buff->is_eop)) {
3028c2ecf20Sopenharmony_ci			u64_stats_update_begin(&self->stats.tx.syncp);
3038c2ecf20Sopenharmony_ci			++self->stats.tx.packets;
3048c2ecf20Sopenharmony_ci			self->stats.tx.bytes += buff->skb->len;
3058c2ecf20Sopenharmony_ci			u64_stats_update_end(&self->stats.tx.syncp);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci			dev_kfree_skb_any(buff->skb);
3088c2ecf20Sopenharmony_ci		}
3098c2ecf20Sopenharmony_ci		buff->pa = 0U;
3108c2ecf20Sopenharmony_ci		buff->eop_index = 0xffffU;
3118c2ecf20Sopenharmony_ci		self->sw_head = aq_ring_next_dx(self, self->sw_head);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return !!budget;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic void aq_rx_checksum(struct aq_ring_s *self,
3188c2ecf20Sopenharmony_ci			   struct aq_ring_buff_s *buff,
3198c2ecf20Sopenharmony_ci			   struct sk_buff *skb)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	if (!(self->aq_nic->ndev->features & NETIF_F_RXCSUM))
3228c2ecf20Sopenharmony_ci		return;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (unlikely(buff->is_cso_err)) {
3258c2ecf20Sopenharmony_ci		u64_stats_update_begin(&self->stats.rx.syncp);
3268c2ecf20Sopenharmony_ci		++self->stats.rx.errors;
3278c2ecf20Sopenharmony_ci		u64_stats_update_end(&self->stats.rx.syncp);
3288c2ecf20Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
3298c2ecf20Sopenharmony_ci		return;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	if (buff->is_ip_cso) {
3328c2ecf20Sopenharmony_ci		__skb_incr_checksum_unnecessary(skb);
3338c2ecf20Sopenharmony_ci	} else {
3348c2ecf20Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (buff->is_udp_cso || buff->is_tcp_cso)
3388c2ecf20Sopenharmony_ci		__skb_incr_checksum_unnecessary(skb);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
3428c2ecf20Sopenharmony_ciint aq_ring_rx_clean(struct aq_ring_s *self,
3438c2ecf20Sopenharmony_ci		     struct napi_struct *napi,
3448c2ecf20Sopenharmony_ci		     int *work_done,
3458c2ecf20Sopenharmony_ci		     int budget)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct net_device *ndev = aq_nic_get_ndev(self->aq_nic);
3488c2ecf20Sopenharmony_ci	int err = 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	for (; (self->sw_head != self->hw_head) && budget;
3518c2ecf20Sopenharmony_ci		self->sw_head = aq_ring_next_dx(self, self->sw_head),
3528c2ecf20Sopenharmony_ci		--budget, ++(*work_done)) {
3538c2ecf20Sopenharmony_ci		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
3548c2ecf20Sopenharmony_ci		bool is_ptp_ring = aq_ptp_ring(self->aq_nic, self);
3558c2ecf20Sopenharmony_ci		struct aq_ring_buff_s *buff_ = NULL;
3568c2ecf20Sopenharmony_ci		struct sk_buff *skb = NULL;
3578c2ecf20Sopenharmony_ci		unsigned int next_ = 0U;
3588c2ecf20Sopenharmony_ci		unsigned int i = 0U;
3598c2ecf20Sopenharmony_ci		u16 hdr_len;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		if (buff->is_cleaned)
3628c2ecf20Sopenharmony_ci			continue;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		if (!buff->is_eop) {
3658c2ecf20Sopenharmony_ci			unsigned int frag_cnt = 0U;
3668c2ecf20Sopenharmony_ci			buff_ = buff;
3678c2ecf20Sopenharmony_ci			do {
3688c2ecf20Sopenharmony_ci				bool is_rsc_completed = true;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci				if (buff_->next >= self->size) {
3718c2ecf20Sopenharmony_ci					err = -EIO;
3728c2ecf20Sopenharmony_ci					goto err_exit;
3738c2ecf20Sopenharmony_ci				}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci				frag_cnt++;
3768c2ecf20Sopenharmony_ci				next_ = buff_->next,
3778c2ecf20Sopenharmony_ci				buff_ = &self->buff_ring[next_];
3788c2ecf20Sopenharmony_ci				is_rsc_completed =
3798c2ecf20Sopenharmony_ci					aq_ring_dx_in_range(self->sw_head,
3808c2ecf20Sopenharmony_ci							    next_,
3818c2ecf20Sopenharmony_ci							    self->hw_head);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci				if (unlikely(!is_rsc_completed) ||
3848c2ecf20Sopenharmony_ci						frag_cnt > MAX_SKB_FRAGS) {
3858c2ecf20Sopenharmony_ci					err = 0;
3868c2ecf20Sopenharmony_ci					goto err_exit;
3878c2ecf20Sopenharmony_ci				}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci				buff->is_error |= buff_->is_error;
3908c2ecf20Sopenharmony_ci				buff->is_cso_err |= buff_->is_cso_err;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci			} while (!buff_->is_eop);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci			if (buff->is_error ||
3958c2ecf20Sopenharmony_ci			    (buff->is_lro && buff->is_cso_err)) {
3968c2ecf20Sopenharmony_ci				buff_ = buff;
3978c2ecf20Sopenharmony_ci				do {
3988c2ecf20Sopenharmony_ci					if (buff_->next >= self->size) {
3998c2ecf20Sopenharmony_ci						err = -EIO;
4008c2ecf20Sopenharmony_ci						goto err_exit;
4018c2ecf20Sopenharmony_ci					}
4028c2ecf20Sopenharmony_ci					next_ = buff_->next,
4038c2ecf20Sopenharmony_ci					buff_ = &self->buff_ring[next_];
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci					buff_->is_cleaned = true;
4068c2ecf20Sopenharmony_ci				} while (!buff_->is_eop);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci				u64_stats_update_begin(&self->stats.rx.syncp);
4098c2ecf20Sopenharmony_ci				++self->stats.rx.errors;
4108c2ecf20Sopenharmony_ci				u64_stats_update_end(&self->stats.rx.syncp);
4118c2ecf20Sopenharmony_ci				continue;
4128c2ecf20Sopenharmony_ci			}
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		if (buff->is_error) {
4168c2ecf20Sopenharmony_ci			u64_stats_update_begin(&self->stats.rx.syncp);
4178c2ecf20Sopenharmony_ci			++self->stats.rx.errors;
4188c2ecf20Sopenharmony_ci			u64_stats_update_end(&self->stats.rx.syncp);
4198c2ecf20Sopenharmony_ci			continue;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		dma_sync_single_range_for_cpu(aq_nic_get_dev(self->aq_nic),
4238c2ecf20Sopenharmony_ci					      buff->rxdata.daddr,
4248c2ecf20Sopenharmony_ci					      buff->rxdata.pg_off,
4258c2ecf20Sopenharmony_ci					      buff->len, DMA_FROM_DEVICE);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		skb = napi_alloc_skb(napi, AQ_CFG_RX_HDR_SIZE);
4288c2ecf20Sopenharmony_ci		if (unlikely(!skb)) {
4298c2ecf20Sopenharmony_ci			u64_stats_update_begin(&self->stats.rx.syncp);
4308c2ecf20Sopenharmony_ci			self->stats.rx.skb_alloc_fails++;
4318c2ecf20Sopenharmony_ci			u64_stats_update_end(&self->stats.rx.syncp);
4328c2ecf20Sopenharmony_ci			err = -ENOMEM;
4338c2ecf20Sopenharmony_ci			goto err_exit;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci		if (is_ptp_ring)
4368c2ecf20Sopenharmony_ci			buff->len -=
4378c2ecf20Sopenharmony_ci				aq_ptp_extract_ts(self->aq_nic, skb,
4388c2ecf20Sopenharmony_ci						  aq_buf_vaddr(&buff->rxdata),
4398c2ecf20Sopenharmony_ci						  buff->len);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		hdr_len = buff->len;
4428c2ecf20Sopenharmony_ci		if (hdr_len > AQ_CFG_RX_HDR_SIZE)
4438c2ecf20Sopenharmony_ci			hdr_len = eth_get_headlen(skb->dev,
4448c2ecf20Sopenharmony_ci						  aq_buf_vaddr(&buff->rxdata),
4458c2ecf20Sopenharmony_ci						  AQ_CFG_RX_HDR_SIZE);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		memcpy(__skb_put(skb, hdr_len), aq_buf_vaddr(&buff->rxdata),
4488c2ecf20Sopenharmony_ci		       ALIGN(hdr_len, sizeof(long)));
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		if (buff->len - hdr_len > 0) {
4518c2ecf20Sopenharmony_ci			skb_add_rx_frag(skb, i++, buff->rxdata.page,
4528c2ecf20Sopenharmony_ci					buff->rxdata.pg_off + hdr_len,
4538c2ecf20Sopenharmony_ci					buff->len - hdr_len,
4548c2ecf20Sopenharmony_ci					AQ_CFG_RX_FRAME_MAX);
4558c2ecf20Sopenharmony_ci			page_ref_inc(buff->rxdata.page);
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (!buff->is_eop) {
4598c2ecf20Sopenharmony_ci			buff_ = buff;
4608c2ecf20Sopenharmony_ci			do {
4618c2ecf20Sopenharmony_ci				next_ = buff_->next;
4628c2ecf20Sopenharmony_ci				buff_ = &self->buff_ring[next_];
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci				dma_sync_single_range_for_cpu(aq_nic_get_dev(self->aq_nic),
4658c2ecf20Sopenharmony_ci							      buff_->rxdata.daddr,
4668c2ecf20Sopenharmony_ci							      buff_->rxdata.pg_off,
4678c2ecf20Sopenharmony_ci							      buff_->len,
4688c2ecf20Sopenharmony_ci							      DMA_FROM_DEVICE);
4698c2ecf20Sopenharmony_ci				skb_add_rx_frag(skb, i++,
4708c2ecf20Sopenharmony_ci						buff_->rxdata.page,
4718c2ecf20Sopenharmony_ci						buff_->rxdata.pg_off,
4728c2ecf20Sopenharmony_ci						buff_->len,
4738c2ecf20Sopenharmony_ci						AQ_CFG_RX_FRAME_MAX);
4748c2ecf20Sopenharmony_ci				page_ref_inc(buff_->rxdata.page);
4758c2ecf20Sopenharmony_ci				buff_->is_cleaned = 1;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci				buff->is_ip_cso &= buff_->is_ip_cso;
4788c2ecf20Sopenharmony_ci				buff->is_udp_cso &= buff_->is_udp_cso;
4798c2ecf20Sopenharmony_ci				buff->is_tcp_cso &= buff_->is_tcp_cso;
4808c2ecf20Sopenharmony_ci				buff->is_cso_err |= buff_->is_cso_err;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci			} while (!buff_->is_eop);
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		if (buff->is_vlan)
4868c2ecf20Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
4878c2ecf20Sopenharmony_ci					       buff->vlan_rx_tag);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, ndev);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		aq_rx_checksum(self, buff, skb);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		skb_set_hash(skb, buff->rss_hash,
4948c2ecf20Sopenharmony_ci			     buff->is_hash_l4 ? PKT_HASH_TYPE_L4 :
4958c2ecf20Sopenharmony_ci			     PKT_HASH_TYPE_NONE);
4968c2ecf20Sopenharmony_ci		/* Send all PTP traffic to 0 queue */
4978c2ecf20Sopenharmony_ci		skb_record_rx_queue(skb,
4988c2ecf20Sopenharmony_ci				    is_ptp_ring ? 0
4998c2ecf20Sopenharmony_ci						: AQ_NIC_RING2QMAP(self->aq_nic,
5008c2ecf20Sopenharmony_ci								   self->idx));
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		u64_stats_update_begin(&self->stats.rx.syncp);
5038c2ecf20Sopenharmony_ci		++self->stats.rx.packets;
5048c2ecf20Sopenharmony_ci		self->stats.rx.bytes += skb->len;
5058c2ecf20Sopenharmony_ci		u64_stats_update_end(&self->stats.rx.syncp);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		napi_gro_receive(napi, skb);
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cierr_exit:
5118c2ecf20Sopenharmony_ci	return err;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_civoid aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
5178c2ecf20Sopenharmony_ci	while (self->sw_head != self->hw_head) {
5188c2ecf20Sopenharmony_ci		u64 ns;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		aq_nic->aq_hw_ops->extract_hwts(aq_nic->aq_hw,
5218c2ecf20Sopenharmony_ci						self->dx_ring +
5228c2ecf20Sopenharmony_ci						(self->sw_head * self->dx_size),
5238c2ecf20Sopenharmony_ci						self->dx_size, &ns);
5248c2ecf20Sopenharmony_ci		aq_ptp_tx_hwtstamp(aq_nic, ns);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		self->sw_head = aq_ring_next_dx(self, self->sw_head);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci#endif
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ciint aq_ring_rx_fill(struct aq_ring_s *self)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	unsigned int page_order = self->page_order;
5348c2ecf20Sopenharmony_ci	struct aq_ring_buff_s *buff = NULL;
5358c2ecf20Sopenharmony_ci	int err = 0;
5368c2ecf20Sopenharmony_ci	int i = 0;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (aq_ring_avail_dx(self) < min_t(unsigned int, AQ_CFG_RX_REFILL_THRES,
5398c2ecf20Sopenharmony_ci					   self->size / 2))
5408c2ecf20Sopenharmony_ci		return err;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	for (i = aq_ring_avail_dx(self); i--;
5438c2ecf20Sopenharmony_ci		self->sw_tail = aq_ring_next_dx(self, self->sw_tail)) {
5448c2ecf20Sopenharmony_ci		buff = &self->buff_ring[self->sw_tail];
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		buff->flags = 0U;
5478c2ecf20Sopenharmony_ci		buff->len = AQ_CFG_RX_FRAME_MAX;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		err = aq_get_rxpages(self, buff, page_order);
5508c2ecf20Sopenharmony_ci		if (err)
5518c2ecf20Sopenharmony_ci			goto err_exit;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		buff->pa = aq_buf_daddr(&buff->rxdata);
5548c2ecf20Sopenharmony_ci		buff = NULL;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cierr_exit:
5588c2ecf20Sopenharmony_ci	return err;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_civoid aq_ring_rx_deinit(struct aq_ring_s *self)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	if (!self)
5648c2ecf20Sopenharmony_ci		return;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	for (; self->sw_head != self->sw_tail;
5678c2ecf20Sopenharmony_ci		self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
5688c2ecf20Sopenharmony_ci		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		aq_free_rxpage(&buff->rxdata, aq_nic_get_dev(self->aq_nic));
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_civoid aq_ring_free(struct aq_ring_s *self)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	if (!self)
5778c2ecf20Sopenharmony_ci		return;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	kfree(self->buff_ring);
5808c2ecf20Sopenharmony_ci	self->buff_ring = NULL;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (self->dx_ring) {
5838c2ecf20Sopenharmony_ci		dma_free_coherent(aq_nic_get_dev(self->aq_nic),
5848c2ecf20Sopenharmony_ci				  self->size * self->dx_size, self->dx_ring,
5858c2ecf20Sopenharmony_ci				  self->dx_ring_pa);
5868c2ecf20Sopenharmony_ci		self->dx_ring = NULL;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ciunsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	unsigned int count;
5938c2ecf20Sopenharmony_ci	unsigned int start;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (self->ring_type == ATL_RING_RX) {
5968c2ecf20Sopenharmony_ci		/* This data should mimic aq_ethtool_queue_rx_stat_names structure */
5978c2ecf20Sopenharmony_ci		do {
5988c2ecf20Sopenharmony_ci			count = 0;
5998c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&self->stats.rx.syncp);
6008c2ecf20Sopenharmony_ci			data[count] = self->stats.rx.packets;
6018c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.jumbo_packets;
6028c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.lro_packets;
6038c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.errors;
6048c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.alloc_fails;
6058c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.skb_alloc_fails;
6068c2ecf20Sopenharmony_ci			data[++count] = self->stats.rx.polls;
6078c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&self->stats.rx.syncp, start));
6088c2ecf20Sopenharmony_ci	} else {
6098c2ecf20Sopenharmony_ci		/* This data should mimic aq_ethtool_queue_tx_stat_names structure */
6108c2ecf20Sopenharmony_ci		do {
6118c2ecf20Sopenharmony_ci			count = 0;
6128c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&self->stats.tx.syncp);
6138c2ecf20Sopenharmony_ci			data[count] = self->stats.tx.packets;
6148c2ecf20Sopenharmony_ci			data[++count] = self->stats.tx.queue_restarts;
6158c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&self->stats.tx.syncp, start));
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return ++count;
6198c2ecf20Sopenharmony_ci}
620