diff options
Diffstat (limited to 'drivers/net/ethernet/aquantia/atlantic/aq_vec.c')
| -rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/aq_vec.c | 223 |
1 files changed, 103 insertions, 120 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index ad5b4d4dac7f..9769ab4f9bef 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -1,10 +1,8 @@ -/* - * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved +// SPDX-License-Identifier: GPL-2.0-only +/* Atlantic Network Driver * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. + * Copyright (C) 2014-2019 aQuantia Corporation + * Copyright (C) 2019-2020 Marvell International Ltd. */ /* File aq_vec.c: Definition of common structure for vector of Rx and Tx rings. @@ -12,15 +10,9 @@ */ #include "aq_vec.h" -#include "aq_nic.h" -#include "aq_ring.h" -#include "aq_hw.h" - -#include <linux/netdevice.h> struct aq_vec_s { - struct aq_obj_s header; - struct aq_hw_ops *aq_hw_ops; + const struct aq_hw_ops *aq_hw_ops; struct aq_hw_s *aq_hw; struct aq_nic_s *aq_nic; unsigned int tx_rings; @@ -34,22 +26,23 @@ struct aq_vec_s { #define AQ_VEC_RX_ID 1 static int aq_vec_poll(struct napi_struct *napi, int budget) -__releases(&self->lock) -__acquires(&self->lock) { struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi); + unsigned int sw_tail_old = 0U; struct aq_ring_s *ring = NULL; + bool was_tx_cleaned = true; + unsigned int i = 0U; int work_done = 0; int err = 0; - unsigned int i = 0U; - unsigned int sw_tail_old = 0U; - bool was_tx_cleaned = false; if (!self) { err = -EINVAL; - } else if (spin_trylock(&self->header.lock)) { - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { + } else { + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; + u64_stats_update_begin(&ring[AQ_VEC_RX_ID].stats.rx.syncp); + ring[AQ_VEC_RX_ID].stats.rx.polls++; + u64_stats_update_end(&ring[AQ_VEC_RX_ID].stats.rx.syncp); if (self->aq_hw_ops->hw_ring_tx_head_update) { err = self->aq_hw_ops->hw_ring_tx_head_update( self->aq_hw, @@ -60,14 +53,8 @@ __acquires(&self->lock) if (ring[AQ_VEC_TX_ID].sw_head != ring[AQ_VEC_TX_ID].hw_head) { - aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); - - if (aq_ring_avail_dx(&ring[AQ_VEC_TX_ID]) > - AQ_CFG_SKB_FRAGS_MAX) { - aq_nic_ndev_queue_start(self->aq_nic, - ring[AQ_VEC_TX_ID].idx); - } - was_tx_cleaned = true; + was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); + aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]); } err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw, @@ -78,6 +65,7 @@ __acquires(&self->lock) if (ring[AQ_VEC_RX_ID].sw_head != ring[AQ_VEC_RX_ID].hw_head) { err = aq_ring_rx_clean(&ring[AQ_VEC_RX_ID], + napi, &work_done, budget - work_done); if (err < 0) @@ -97,7 +85,8 @@ __acquires(&self->lock) } } - if (was_tx_cleaned) +err_exit: + if (!was_tx_cleaned) work_done = budget; if (work_done < budget) { @@ -105,9 +94,6 @@ __acquires(&self->lock) self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U << self->aq_ring_param.vec_idx); } - -err_exit: - spin_unlock(&self->header.lock); } return work_done; @@ -117,15 +103,10 @@ struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg) { struct aq_vec_s *self = NULL; - struct aq_ring_s *ring = NULL; - unsigned int i = 0U; - int err = 0; self = kzalloc(sizeof(*self), GFP_KERNEL); - if (!self) { - err = -ENOMEM; + if (!self) goto err_exit; - } self->aq_nic = aq_nic; self->aq_ring_param.vec_idx = idx; @@ -138,44 +119,65 @@ struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx, self->tx_rings = 0; self->rx_rings = 0; - netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi, - aq_vec_poll, AQ_CFG_NAPI_WEIGHT); + netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi, aq_vec_poll); + +err_exit: + return self; +} + +int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic, + unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg) +{ + struct aq_ring_s *ring = NULL; + unsigned int i = 0U; + int err = 0; for (i = 0; i < aq_nic_cfg->tcs; ++i) { - unsigned int idx_ring = AQ_NIC_TCVEC2RING(self->nic, - self->tx_rings, - self->aq_ring_param.vec_idx); + const unsigned int idx_ring = AQ_NIC_CFG_TCVEC2RING(aq_nic_cfg, + i, idx); - ring = aq_ring_tx_alloc(&self->ring[i][AQ_VEC_TX_ID], aq_nic, - idx_ring, aq_nic_cfg); - if (!ring) { - err = -ENOMEM; + ring = &self->ring[i][AQ_VEC_TX_ID]; + err = aq_ring_tx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg); + if (err) goto err_exit; - } ++self->tx_rings; aq_nic_set_tx_ring(aq_nic, idx_ring, ring); - ring = aq_ring_rx_alloc(&self->ring[i][AQ_VEC_RX_ID], aq_nic, - idx_ring, aq_nic_cfg); - if (!ring) { + ring = &self->ring[i][AQ_VEC_RX_ID]; + if (xdp_rxq_info_reg(&ring->xdp_rxq, + aq_nic->ndev, idx, + self->napi.napi_id) < 0) { + err = -ENOMEM; + goto err_exit; + } + if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_PAGE_SHARED, NULL) < 0) { + xdp_rxq_info_unreg(&ring->xdp_rxq); err = -ENOMEM; goto err_exit; } + err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg); + if (err) { + xdp_rxq_info_unreg(&ring->xdp_rxq); + goto err_exit; + } + ++self->rx_rings; } err_exit: if (err < 0) { - aq_vec_free(self); + aq_vec_ring_free(self); self = NULL; } - return self; + + return err; } -int aq_vec_init(struct aq_vec_s *self, struct aq_hw_ops *aq_hw_ops, +int aq_vec_init(struct aq_vec_s *self, const struct aq_hw_ops *aq_hw_ops, struct aq_hw_s *aq_hw) { struct aq_ring_s *ring = NULL; @@ -185,11 +187,9 @@ int aq_vec_init(struct aq_vec_s *self, struct aq_hw_ops *aq_hw_ops, self->aq_hw_ops = aq_hw_ops; self->aq_hw = aq_hw; - spin_lock_init(&self->header.lock); - - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { - err = aq_ring_init(&ring[AQ_VEC_TX_ID]); + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; + err = aq_ring_init(&ring[AQ_VEC_TX_ID], ATL_RING_TX); if (err < 0) goto err_exit; @@ -199,7 +199,7 @@ int aq_vec_init(struct aq_vec_s *self, struct aq_hw_ops *aq_hw_ops, if (err < 0) goto err_exit; - err = aq_ring_init(&ring[AQ_VEC_RX_ID]); + err = aq_ring_init(&ring[AQ_VEC_RX_ID], ATL_RING_RX); if (err < 0) goto err_exit; @@ -229,8 +229,8 @@ int aq_vec_start(struct aq_vec_s *self) unsigned int i = 0U; int err = 0; - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; err = self->aq_hw_ops->hw_ring_tx_start(self->aq_hw, &ring[AQ_VEC_TX_ID]); if (err < 0) @@ -253,8 +253,8 @@ void aq_vec_stop(struct aq_vec_s *self) struct aq_ring_s *ring = NULL; unsigned int i = 0U; - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; self->aq_hw_ops->hw_ring_tx_stop(self->aq_hw, &ring[AQ_VEC_TX_ID]); @@ -273,32 +273,46 @@ void aq_vec_deinit(struct aq_vec_s *self) if (!self) goto err_exit; - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]); } + err_exit:; } void aq_vec_free(struct aq_vec_s *self) { + if (!self) + goto err_exit; + + netif_napi_del(&self->napi); + + kfree(self); + +err_exit:; +} + +void aq_vec_ring_free(struct aq_vec_s *self) +{ struct aq_ring_s *ring = NULL; unsigned int i = 0U; if (!self) goto err_exit; - for (i = 0U, ring = self->ring[0]; - self->tx_rings > i; ++i, ring = self->ring[i]) { + for (i = 0U; self->tx_rings > i; ++i) { + ring = self->ring[i]; aq_ring_free(&ring[AQ_VEC_TX_ID]); - aq_ring_free(&ring[AQ_VEC_RX_ID]); + if (i < self->rx_rings) { + xdp_rxq_info_unreg(&ring[AQ_VEC_RX_ID].xdp_rxq); + aq_ring_free(&ring[AQ_VEC_RX_ID]); + } } - netif_napi_del(&self->napi); - - kfree(self); - + self->tx_rings = 0; + self->rx_rings = 0; err_exit:; } @@ -321,15 +335,13 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) { struct aq_vec_s *self = private; u64 irq_mask = 0U; - irqreturn_t err = 0; + int err; - if (!self) { - err = -EINVAL; - goto err_exit; - } + if (!self) + return IRQ_NONE; err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask); if (err < 0) - goto err_exit; + return IRQ_NONE; if (irq_mask) { self->aq_hw_ops->hw_irq_disable(self->aq_hw, @@ -337,11 +349,10 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) napi_schedule(&self->napi); } else { self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U); - err = IRQ_NONE; + return IRQ_NONE; } -err_exit: - return err >= 0 ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self) @@ -349,48 +360,20 @@ cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self) return &self->aq_ring_param.affinity_mask; } -void aq_vec_add_stats(struct aq_vec_s *self, - struct aq_ring_stats_rx_s *stats_rx, - struct aq_ring_stats_tx_s *stats_tx) +bool aq_vec_is_valid_tc(struct aq_vec_s *self, const unsigned int tc) { - struct aq_ring_s *ring = NULL; - unsigned int r = 0U; - - for (r = 0U, ring = self->ring[0]; - self->tx_rings > r; ++r, ring = self->ring[r]) { - struct aq_ring_stats_tx_s *tx = &ring[AQ_VEC_TX_ID].stats.tx; - struct aq_ring_stats_rx_s *rx = &ring[AQ_VEC_RX_ID].stats.rx; - - stats_rx->packets += rx->packets; - stats_rx->bytes += rx->bytes; - stats_rx->errors += rx->errors; - stats_rx->jumbo_packets += rx->jumbo_packets; - stats_rx->lro_packets += rx->lro_packets; - - stats_tx->packets += tx->packets; - stats_tx->bytes += tx->bytes; - stats_tx->errors += tx->errors; - } + return tc < self->rx_rings && tc < self->tx_rings; } -int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count) +unsigned int aq_vec_get_sw_stats(struct aq_vec_s *self, const unsigned int tc, u64 *data) { - unsigned int count = 0U; - struct aq_ring_stats_rx_s stats_rx; - struct aq_ring_stats_tx_s stats_tx; - - memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s)); - memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); - aq_vec_add_stats(self, &stats_rx, &stats_tx); + unsigned int count; - data[count] += stats_rx.packets; - data[++count] += stats_tx.packets; - data[++count] += stats_rx.jumbo_packets; - data[++count] += stats_rx.lro_packets; - data[++count] += stats_rx.errors; + if (!aq_vec_is_valid_tc(self, tc)) + return 0; - if (p_count) - *p_count = ++count; + count = aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_RX_ID], data); + count += aq_ring_fill_stats_data(&self->ring[tc][AQ_VEC_TX_ID], data + count); - return 0; + return count; } |
