162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Atlantic Network Driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation
562306a36Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* File aq_vec.c: Definition of common structure for vector of Rx and Tx rings.
962306a36Sopenharmony_ci * Definition of functions for Rx and Tx rings. Friendly module for aq_nic.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "aq_vec.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct aq_vec_s {
1562306a36Sopenharmony_ci	const struct aq_hw_ops *aq_hw_ops;
1662306a36Sopenharmony_ci	struct aq_hw_s *aq_hw;
1762306a36Sopenharmony_ci	struct aq_nic_s *aq_nic;
1862306a36Sopenharmony_ci	unsigned int tx_rings;
1962306a36Sopenharmony_ci	unsigned int rx_rings;
2062306a36Sopenharmony_ci	struct aq_ring_param_s aq_ring_param;
2162306a36Sopenharmony_ci	struct napi_struct napi;
2262306a36Sopenharmony_ci	struct aq_ring_s ring[AQ_CFG_TCS_MAX][2];
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define AQ_VEC_TX_ID 0
2662306a36Sopenharmony_ci#define AQ_VEC_RX_ID 1
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int aq_vec_poll(struct napi_struct *napi, int budget)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
3162306a36Sopenharmony_ci	unsigned int sw_tail_old = 0U;
3262306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
3362306a36Sopenharmony_ci	bool was_tx_cleaned = true;
3462306a36Sopenharmony_ci	unsigned int i = 0U;
3562306a36Sopenharmony_ci	int work_done = 0;
3662306a36Sopenharmony_ci	int err = 0;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (!self) {
3962306a36Sopenharmony_ci		err = -EINVAL;
4062306a36Sopenharmony_ci	} else {
4162306a36Sopenharmony_ci		for (i = 0U; self->tx_rings > i; ++i) {
4262306a36Sopenharmony_ci			ring = self->ring[i];
4362306a36Sopenharmony_ci			u64_stats_update_begin(&ring[AQ_VEC_RX_ID].stats.rx.syncp);
4462306a36Sopenharmony_ci			ring[AQ_VEC_RX_ID].stats.rx.polls++;
4562306a36Sopenharmony_ci			u64_stats_update_end(&ring[AQ_VEC_RX_ID].stats.rx.syncp);
4662306a36Sopenharmony_ci			if (self->aq_hw_ops->hw_ring_tx_head_update) {
4762306a36Sopenharmony_ci				err = self->aq_hw_ops->hw_ring_tx_head_update(
4862306a36Sopenharmony_ci							self->aq_hw,
4962306a36Sopenharmony_ci							&ring[AQ_VEC_TX_ID]);
5062306a36Sopenharmony_ci				if (err < 0)
5162306a36Sopenharmony_ci					goto err_exit;
5262306a36Sopenharmony_ci			}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci			if (ring[AQ_VEC_TX_ID].sw_head !=
5562306a36Sopenharmony_ci			    ring[AQ_VEC_TX_ID].hw_head) {
5662306a36Sopenharmony_ci				was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
5762306a36Sopenharmony_ci				aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]);
5862306a36Sopenharmony_ci			}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci			err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
6162306a36Sopenharmony_ci					    &ring[AQ_VEC_RX_ID]);
6262306a36Sopenharmony_ci			if (err < 0)
6362306a36Sopenharmony_ci				goto err_exit;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci			if (ring[AQ_VEC_RX_ID].sw_head !=
6662306a36Sopenharmony_ci				ring[AQ_VEC_RX_ID].hw_head) {
6762306a36Sopenharmony_ci				err = aq_ring_rx_clean(&ring[AQ_VEC_RX_ID],
6862306a36Sopenharmony_ci						       napi,
6962306a36Sopenharmony_ci						       &work_done,
7062306a36Sopenharmony_ci						       budget - work_done);
7162306a36Sopenharmony_ci				if (err < 0)
7262306a36Sopenharmony_ci					goto err_exit;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci				sw_tail_old = ring[AQ_VEC_RX_ID].sw_tail;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci				err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
7762306a36Sopenharmony_ci				if (err < 0)
7862306a36Sopenharmony_ci					goto err_exit;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci				err = self->aq_hw_ops->hw_ring_rx_fill(
8162306a36Sopenharmony_ci					self->aq_hw,
8262306a36Sopenharmony_ci					&ring[AQ_VEC_RX_ID], sw_tail_old);
8362306a36Sopenharmony_ci				if (err < 0)
8462306a36Sopenharmony_ci					goto err_exit;
8562306a36Sopenharmony_ci			}
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cierr_exit:
8962306a36Sopenharmony_ci		if (!was_tx_cleaned)
9062306a36Sopenharmony_ci			work_done = budget;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		if (work_done < budget) {
9362306a36Sopenharmony_ci			napi_complete_done(napi, work_done);
9462306a36Sopenharmony_ci			self->aq_hw_ops->hw_irq_enable(self->aq_hw,
9562306a36Sopenharmony_ci					1U << self->aq_ring_param.vec_idx);
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return work_done;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
10362306a36Sopenharmony_ci			      struct aq_nic_cfg_s *aq_nic_cfg)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct aq_vec_s *self = NULL;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	self = kzalloc(sizeof(*self), GFP_KERNEL);
10862306a36Sopenharmony_ci	if (!self)
10962306a36Sopenharmony_ci		goto err_exit;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	self->aq_nic = aq_nic;
11262306a36Sopenharmony_ci	self->aq_ring_param.vec_idx = idx;
11362306a36Sopenharmony_ci	self->aq_ring_param.cpu =
11462306a36Sopenharmony_ci		idx + aq_nic_cfg->aq_rss.base_cpu_number;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	cpumask_set_cpu(self->aq_ring_param.cpu,
11762306a36Sopenharmony_ci			&self->aq_ring_param.affinity_mask);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	self->tx_rings = 0;
12062306a36Sopenharmony_ci	self->rx_rings = 0;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi, aq_vec_poll);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cierr_exit:
12562306a36Sopenharmony_ci	return self;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciint aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
12962306a36Sopenharmony_ci		      unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
13262306a36Sopenharmony_ci	unsigned int i = 0U;
13362306a36Sopenharmony_ci	int err = 0;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (i = 0; i < aq_nic_cfg->tcs; ++i) {
13662306a36Sopenharmony_ci		const unsigned int idx_ring = AQ_NIC_CFG_TCVEC2RING(aq_nic_cfg,
13762306a36Sopenharmony_ci								    i, idx);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		ring = &self->ring[i][AQ_VEC_TX_ID];
14062306a36Sopenharmony_ci		err = aq_ring_tx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
14162306a36Sopenharmony_ci		if (err)
14262306a36Sopenharmony_ci			goto err_exit;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		++self->tx_rings;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		ring = &self->ring[i][AQ_VEC_RX_ID];
14962306a36Sopenharmony_ci		if (xdp_rxq_info_reg(&ring->xdp_rxq,
15062306a36Sopenharmony_ci				     aq_nic->ndev, idx,
15162306a36Sopenharmony_ci				     self->napi.napi_id) < 0) {
15262306a36Sopenharmony_ci			err = -ENOMEM;
15362306a36Sopenharmony_ci			goto err_exit;
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci		if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
15662306a36Sopenharmony_ci					       MEM_TYPE_PAGE_SHARED, NULL) < 0) {
15762306a36Sopenharmony_ci			xdp_rxq_info_unreg(&ring->xdp_rxq);
15862306a36Sopenharmony_ci			err = -ENOMEM;
15962306a36Sopenharmony_ci			goto err_exit;
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
16362306a36Sopenharmony_ci		if (err) {
16462306a36Sopenharmony_ci			xdp_rxq_info_unreg(&ring->xdp_rxq);
16562306a36Sopenharmony_ci			goto err_exit;
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		++self->rx_rings;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cierr_exit:
17262306a36Sopenharmony_ci	if (err < 0) {
17362306a36Sopenharmony_ci		aq_vec_ring_free(self);
17462306a36Sopenharmony_ci		self = NULL;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return err;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciint aq_vec_init(struct aq_vec_s *self, const struct aq_hw_ops *aq_hw_ops,
18162306a36Sopenharmony_ci		struct aq_hw_s *aq_hw)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
18462306a36Sopenharmony_ci	unsigned int i = 0U;
18562306a36Sopenharmony_ci	int err = 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	self->aq_hw_ops = aq_hw_ops;
18862306a36Sopenharmony_ci	self->aq_hw = aq_hw;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	for (i = 0U; self->tx_rings > i; ++i) {
19162306a36Sopenharmony_ci		ring = self->ring[i];
19262306a36Sopenharmony_ci		err = aq_ring_init(&ring[AQ_VEC_TX_ID], ATL_RING_TX);
19362306a36Sopenharmony_ci		if (err < 0)
19462306a36Sopenharmony_ci			goto err_exit;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		err = self->aq_hw_ops->hw_ring_tx_init(self->aq_hw,
19762306a36Sopenharmony_ci						       &ring[AQ_VEC_TX_ID],
19862306a36Sopenharmony_ci						       &self->aq_ring_param);
19962306a36Sopenharmony_ci		if (err < 0)
20062306a36Sopenharmony_ci			goto err_exit;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		err = aq_ring_init(&ring[AQ_VEC_RX_ID], ATL_RING_RX);
20362306a36Sopenharmony_ci		if (err < 0)
20462306a36Sopenharmony_ci			goto err_exit;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		err = self->aq_hw_ops->hw_ring_rx_init(self->aq_hw,
20762306a36Sopenharmony_ci						       &ring[AQ_VEC_RX_ID],
20862306a36Sopenharmony_ci						       &self->aq_ring_param);
20962306a36Sopenharmony_ci		if (err < 0)
21062306a36Sopenharmony_ci			goto err_exit;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
21362306a36Sopenharmony_ci		if (err < 0)
21462306a36Sopenharmony_ci			goto err_exit;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		err = self->aq_hw_ops->hw_ring_rx_fill(self->aq_hw,
21762306a36Sopenharmony_ci						       &ring[AQ_VEC_RX_ID], 0U);
21862306a36Sopenharmony_ci		if (err < 0)
21962306a36Sopenharmony_ci			goto err_exit;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cierr_exit:
22362306a36Sopenharmony_ci	return err;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ciint aq_vec_start(struct aq_vec_s *self)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
22962306a36Sopenharmony_ci	unsigned int i = 0U;
23062306a36Sopenharmony_ci	int err = 0;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0U; self->tx_rings > i; ++i) {
23362306a36Sopenharmony_ci		ring = self->ring[i];
23462306a36Sopenharmony_ci		err = self->aq_hw_ops->hw_ring_tx_start(self->aq_hw,
23562306a36Sopenharmony_ci							&ring[AQ_VEC_TX_ID]);
23662306a36Sopenharmony_ci		if (err < 0)
23762306a36Sopenharmony_ci			goto err_exit;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		err = self->aq_hw_ops->hw_ring_rx_start(self->aq_hw,
24062306a36Sopenharmony_ci							&ring[AQ_VEC_RX_ID]);
24162306a36Sopenharmony_ci		if (err < 0)
24262306a36Sopenharmony_ci			goto err_exit;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	napi_enable(&self->napi);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cierr_exit:
24862306a36Sopenharmony_ci	return err;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_civoid aq_vec_stop(struct aq_vec_s *self)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
25462306a36Sopenharmony_ci	unsigned int i = 0U;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	for (i = 0U; self->tx_rings > i; ++i) {
25762306a36Sopenharmony_ci		ring = self->ring[i];
25862306a36Sopenharmony_ci		self->aq_hw_ops->hw_ring_tx_stop(self->aq_hw,
25962306a36Sopenharmony_ci						 &ring[AQ_VEC_TX_ID]);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		self->aq_hw_ops->hw_ring_rx_stop(self->aq_hw,
26262306a36Sopenharmony_ci						 &ring[AQ_VEC_RX_ID]);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	napi_disable(&self->napi);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_civoid aq_vec_deinit(struct aq_vec_s *self)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
27162306a36Sopenharmony_ci	unsigned int i = 0U;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (!self)
27462306a36Sopenharmony_ci		goto err_exit;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	for (i = 0U; self->tx_rings > i; ++i) {
27762306a36Sopenharmony_ci		ring = self->ring[i];
27862306a36Sopenharmony_ci		aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
27962306a36Sopenharmony_ci		aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]);
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cierr_exit:;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_civoid aq_vec_free(struct aq_vec_s *self)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (!self)
28862306a36Sopenharmony_ci		goto err_exit;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	netif_napi_del(&self->napi);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	kfree(self);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cierr_exit:;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_civoid aq_vec_ring_free(struct aq_vec_s *self)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct aq_ring_s *ring = NULL;
30062306a36Sopenharmony_ci	unsigned int i = 0U;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!self)
30362306a36Sopenharmony_ci		goto err_exit;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	for (i = 0U; self->tx_rings > i; ++i) {
30662306a36Sopenharmony_ci		ring = self->ring[i];
30762306a36Sopenharmony_ci		aq_ring_free(&ring[AQ_VEC_TX_ID]);
30862306a36Sopenharmony_ci		if (i < self->rx_rings) {
30962306a36Sopenharmony_ci			xdp_rxq_info_unreg(&ring[AQ_VEC_RX_ID].xdp_rxq);
31062306a36Sopenharmony_ci			aq_ring_free(&ring[AQ_VEC_RX_ID]);
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	self->tx_rings = 0;
31562306a36Sopenharmony_ci	self->rx_rings = 0;
31662306a36Sopenharmony_cierr_exit:;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ciirqreturn_t aq_vec_isr(int irq, void *private)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct aq_vec_s *self = private;
32262306a36Sopenharmony_ci	int err = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!self) {
32562306a36Sopenharmony_ci		err = -EINVAL;
32662306a36Sopenharmony_ci		goto err_exit;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	napi_schedule(&self->napi);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cierr_exit:
33162306a36Sopenharmony_ci	return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciirqreturn_t aq_vec_isr_legacy(int irq, void *private)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct aq_vec_s *self = private;
33762306a36Sopenharmony_ci	u64 irq_mask = 0U;
33862306a36Sopenharmony_ci	int err;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!self)
34162306a36Sopenharmony_ci		return IRQ_NONE;
34262306a36Sopenharmony_ci	err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask);
34362306a36Sopenharmony_ci	if (err < 0)
34462306a36Sopenharmony_ci		return IRQ_NONE;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (irq_mask) {
34762306a36Sopenharmony_ci		self->aq_hw_ops->hw_irq_disable(self->aq_hw,
34862306a36Sopenharmony_ci			      1U << self->aq_ring_param.vec_idx);
34962306a36Sopenharmony_ci		napi_schedule(&self->napi);
35062306a36Sopenharmony_ci	} else {
35162306a36Sopenharmony_ci		self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U);
35262306a36Sopenharmony_ci		return IRQ_NONE;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return IRQ_HANDLED;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cicpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	return &self->aq_ring_param.affinity_mask;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cibool aq_vec_is_valid_tc(struct aq_vec_s *self, const unsigned int tc)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	return tc < self->rx_rings && tc < self->tx_rings;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ciunsigned int aq_vec_get_sw_stats(struct aq_vec_s *self, const unsigned int tc, u64 *data)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	unsigned int count;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!aq_vec_is_valid_tc(self, tc))
37362306a36Sopenharmony_ci		return 0;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	count = aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_RX_ID], data);
37662306a36Sopenharmony_ci	count += aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_TX_ID], data + count);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return count;
37962306a36Sopenharmony_ci}
380