LCOV - code coverage report
Current view: top level - drivers/net/ethernet/aquantia/atlantic - aq_vec.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 114 214 53.3 %
Date: 2022-04-01 13:59:58 Functions: 6 12 50.0 %
Branches: 38 74 51.4 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * aQuantia Corporation Network Driver
       4                 :            :  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
       5                 :            :  */
       6                 :            : 
       7                 :            : /* File aq_vec.c: Definition of common structure for vector of Rx and Tx rings.
       8                 :            :  * Definition of functions for Rx and Tx rings. Friendly module for aq_nic.
       9                 :            :  */
      10                 :            : 
      11                 :            : #include "aq_vec.h"
      12                 :            : #include "aq_nic.h"
      13                 :            : #include "aq_ring.h"
      14                 :            : #include "aq_hw.h"
      15                 :            : 
      16                 :            : #include <linux/netdevice.h>
      17                 :            : 
      18                 :            : struct aq_vec_s {
      19                 :            :         const struct aq_hw_ops *aq_hw_ops;
      20                 :            :         struct aq_hw_s *aq_hw;
      21                 :            :         struct aq_nic_s *aq_nic;
      22                 :            :         unsigned int tx_rings;
      23                 :            :         unsigned int rx_rings;
      24                 :            :         struct aq_ring_param_s aq_ring_param;
      25                 :            :         struct napi_struct napi;
      26                 :            :         struct aq_ring_s ring[AQ_CFG_TCS_MAX][2];
      27                 :            : };
      28                 :            : 
      29                 :            : #define AQ_VEC_TX_ID 0
      30                 :            : #define AQ_VEC_RX_ID 1
      31                 :            : 
      32                 :       4324 : static int aq_vec_poll(struct napi_struct *napi, int budget)
      33                 :            : {
      34                 :       4324 :         struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
      35                 :       4324 :         unsigned int sw_tail_old = 0U;
      36                 :       4324 :         struct aq_ring_s *ring = NULL;
      37                 :       4324 :         bool was_tx_cleaned = true;
      38                 :       4324 :         unsigned int i = 0U;
      39                 :       4324 :         int work_done = 0;
      40                 :       4324 :         int err = 0;
      41                 :            : 
      42         [ +  - ]:       4324 :         if (!self) {
      43                 :            :                 err = -EINVAL;
      44                 :            :         } else {
      45                 :       4324 :                 for (i = 0U, ring = self->ring[0];
      46         [ +  + ]:       8648 :                         self->tx_rings > i; ++i, ring = self->ring[i]) {
      47         [ +  - ]:       4324 :                         if (self->aq_hw_ops->hw_ring_tx_head_update) {
      48                 :       4324 :                                 err = self->aq_hw_ops->hw_ring_tx_head_update(
      49                 :            :                                                         self->aq_hw,
      50                 :            :                                                         &ring[AQ_VEC_TX_ID]);
      51         [ -  + ]:       4324 :                                 if (err < 0)
      52                 :          0 :                                         goto err_exit;
      53                 :            :                         }
      54                 :            : 
      55                 :       4324 :                         if (ring[AQ_VEC_TX_ID].sw_head !=
      56         [ +  + ]:       4324 :                             ring[AQ_VEC_TX_ID].hw_head) {
      57                 :       4262 :                                 was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
      58                 :       4262 :                                 aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]);
      59                 :            :                         }
      60                 :            : 
      61                 :       4324 :                         err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
      62                 :            :                                             &ring[AQ_VEC_RX_ID]);
      63         [ -  + ]:       4324 :                         if (err < 0)
      64                 :          0 :                                 goto err_exit;
      65                 :            : 
      66                 :       4324 :                         if (ring[AQ_VEC_RX_ID].sw_head !=
      67         [ +  + ]:       4324 :                                 ring[AQ_VEC_RX_ID].hw_head) {
      68                 :       4228 :                                 err = aq_ring_rx_clean(&ring[AQ_VEC_RX_ID],
      69                 :            :                                                        napi,
      70                 :            :                                                        &work_done,
      71                 :            :                                                        budget - work_done);
      72         [ -  + ]:       4228 :                                 if (err < 0)
      73                 :          0 :                                         goto err_exit;
      74                 :            : 
      75                 :       4228 :                                 sw_tail_old = ring[AQ_VEC_RX_ID].sw_tail;
      76                 :            : 
      77                 :       4228 :                                 err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
      78         [ -  + ]:       4228 :                                 if (err < 0)
      79                 :          0 :                                         goto err_exit;
      80                 :            : 
      81                 :       4228 :                                 err = self->aq_hw_ops->hw_ring_rx_fill(
      82                 :            :                                         self->aq_hw,
      83                 :            :                                         &ring[AQ_VEC_RX_ID], sw_tail_old);
      84         [ -  + ]:       4228 :                                 if (err < 0)
      85                 :          0 :                                         goto err_exit;
      86                 :            :                         }
      87                 :            :                 }
      88                 :            : 
      89                 :       4324 : err_exit:
      90         [ +  + ]:       4324 :                 if (!was_tx_cleaned)
      91                 :       4135 :                         work_done = budget;
      92                 :            : 
      93         [ +  + ]:       4324 :                 if (work_done < budget) {
      94                 :        189 :                         napi_complete_done(napi, work_done);
      95                 :        189 :                         self->aq_hw_ops->hw_irq_enable(self->aq_hw,
      96                 :        189 :                                         1U << self->aq_ring_param.vec_idx);
      97                 :            :                 }
      98                 :            :         }
      99                 :            : 
     100                 :       4324 :         return work_done;
     101                 :            : }
     102                 :            : 
     103                 :         33 : struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx,
     104                 :            :                               struct aq_nic_cfg_s *aq_nic_cfg)
     105                 :            : {
     106                 :         33 :         struct aq_ring_s *ring = NULL;
     107                 :         33 :         struct aq_vec_s *self = NULL;
     108                 :         33 :         unsigned int i = 0U;
     109                 :         33 :         int err = 0;
     110                 :            : 
     111                 :         33 :         self = kzalloc(sizeof(*self), GFP_KERNEL);
     112         [ -  + ]:         33 :         if (!self) {
     113                 :          0 :                 err = -ENOMEM;
     114                 :          0 :                 goto err_exit;
     115                 :            :         }
     116                 :            : 
     117                 :         33 :         self->aq_nic = aq_nic;
     118                 :         33 :         self->aq_ring_param.vec_idx = idx;
     119                 :         33 :         self->aq_ring_param.cpu =
     120                 :         33 :                 idx + aq_nic_cfg->aq_rss.base_cpu_number;
     121                 :            : 
     122                 :         33 :         cpumask_set_cpu(self->aq_ring_param.cpu,
     123                 :            :                         &self->aq_ring_param.affinity_mask);
     124                 :            : 
     125                 :         33 :         self->tx_rings = 0;
     126                 :         33 :         self->rx_rings = 0;
     127                 :            : 
     128                 :         33 :         netif_napi_add(aq_nic_get_ndev(aq_nic), &self->napi,
     129                 :            :                        aq_vec_poll, AQ_CFG_NAPI_WEIGHT);
     130                 :            : 
     131         [ +  + ]:         99 :         for (i = 0; i < aq_nic_cfg->tcs; ++i) {
     132                 :         33 :                 unsigned int idx_ring = AQ_NIC_TCVEC2RING(self->nic,
     133                 :            :                                                 self->tx_rings,
     134                 :            :                                                 self->aq_ring_param.vec_idx);
     135                 :            : 
     136                 :         33 :                 ring = aq_ring_tx_alloc(&self->ring[i][AQ_VEC_TX_ID], aq_nic,
     137                 :            :                                         idx_ring, aq_nic_cfg);
     138         [ -  + ]:         33 :                 if (!ring) {
     139                 :          0 :                         err = -ENOMEM;
     140                 :          0 :                         goto err_exit;
     141                 :            :                 }
     142                 :            : 
     143                 :         33 :                 ++self->tx_rings;
     144                 :            : 
     145                 :         33 :                 aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
     146                 :            : 
     147                 :         33 :                 ring = aq_ring_rx_alloc(&self->ring[i][AQ_VEC_RX_ID], aq_nic,
     148                 :            :                                         idx_ring, aq_nic_cfg);
     149         [ -  + ]:         33 :                 if (!ring) {
     150                 :          0 :                         err = -ENOMEM;
     151                 :          0 :                         goto err_exit;
     152                 :            :                 }
     153                 :            : 
     154                 :         33 :                 ++self->rx_rings;
     155                 :            :         }
     156                 :            : 
     157                 :         33 : err_exit:
     158                 :          0 :         if (err < 0) {
     159                 :          0 :                 aq_vec_free(self);
     160                 :          0 :                 self = NULL;
     161                 :            :         }
     162                 :            : 
     163                 :         33 :         return self;
     164                 :            : }
     165                 :            : 
     166                 :         33 : int aq_vec_init(struct aq_vec_s *self, const struct aq_hw_ops *aq_hw_ops,
     167                 :            :                 struct aq_hw_s *aq_hw)
     168                 :            : {
     169                 :         33 :         struct aq_ring_s *ring = NULL;
     170                 :         33 :         unsigned int i = 0U;
     171                 :         33 :         int err = 0;
     172                 :            : 
     173                 :         33 :         self->aq_hw_ops = aq_hw_ops;
     174                 :         33 :         self->aq_hw = aq_hw;
     175                 :            : 
     176                 :         33 :         for (i = 0U, ring = self->ring[0];
     177         [ +  + ]:         66 :                 self->tx_rings > i; ++i, ring = self->ring[i]) {
     178                 :         33 :                 err = aq_ring_init(&ring[AQ_VEC_TX_ID]);
     179         [ -  + ]:         33 :                 if (err < 0)
     180                 :          0 :                         goto err_exit;
     181                 :            : 
     182                 :         33 :                 err = self->aq_hw_ops->hw_ring_tx_init(self->aq_hw,
     183                 :            :                                                        &ring[AQ_VEC_TX_ID],
     184                 :            :                                                        &self->aq_ring_param);
     185         [ -  + ]:         33 :                 if (err < 0)
     186                 :          0 :                         goto err_exit;
     187                 :            : 
     188                 :         33 :                 err = aq_ring_init(&ring[AQ_VEC_RX_ID]);
     189         [ -  + ]:         33 :                 if (err < 0)
     190                 :          0 :                         goto err_exit;
     191                 :            : 
     192                 :         33 :                 err = self->aq_hw_ops->hw_ring_rx_init(self->aq_hw,
     193                 :            :                                                        &ring[AQ_VEC_RX_ID],
     194                 :            :                                                        &self->aq_ring_param);
     195         [ -  + ]:         33 :                 if (err < 0)
     196                 :          0 :                         goto err_exit;
     197                 :            : 
     198                 :         33 :                 err = aq_ring_rx_fill(&ring[AQ_VEC_RX_ID]);
     199         [ -  + ]:         33 :                 if (err < 0)
     200                 :          0 :                         goto err_exit;
     201                 :            : 
     202                 :         33 :                 err = self->aq_hw_ops->hw_ring_rx_fill(self->aq_hw,
     203                 :            :                                                        &ring[AQ_VEC_RX_ID], 0U);
     204         [ -  + ]:         33 :                 if (err < 0)
     205                 :          0 :                         goto err_exit;
     206                 :            :         }
     207                 :            : 
     208                 :         33 : err_exit:
     209                 :         33 :         return err;
     210                 :            : }
     211                 :            : 
     212                 :         33 : int aq_vec_start(struct aq_vec_s *self)
     213                 :            : {
     214                 :         33 :         struct aq_ring_s *ring = NULL;
     215                 :         33 :         unsigned int i = 0U;
     216                 :         33 :         int err = 0;
     217                 :            : 
     218                 :         33 :         for (i = 0U, ring = self->ring[0];
     219         [ +  + ]:         66 :                 self->tx_rings > i; ++i, ring = self->ring[i]) {
     220                 :         33 :                 err = self->aq_hw_ops->hw_ring_tx_start(self->aq_hw,
     221                 :            :                                                         &ring[AQ_VEC_TX_ID]);
     222         [ -  + ]:         33 :                 if (err < 0)
     223                 :          0 :                         goto err_exit;
     224                 :            : 
     225                 :         33 :                 err = self->aq_hw_ops->hw_ring_rx_start(self->aq_hw,
     226                 :            :                                                         &ring[AQ_VEC_RX_ID]);
     227         [ -  + ]:         33 :                 if (err < 0)
     228                 :          0 :                         goto err_exit;
     229                 :            :         }
     230                 :            : 
     231                 :         33 :         napi_enable(&self->napi);
     232                 :            : 
     233                 :         33 : err_exit:
     234                 :         33 :         return err;
     235                 :            : }
     236                 :            : 
     237                 :          0 : void aq_vec_stop(struct aq_vec_s *self)
     238                 :            : {
     239                 :          0 :         struct aq_ring_s *ring = NULL;
     240                 :          0 :         unsigned int i = 0U;
     241                 :            : 
     242                 :          0 :         for (i = 0U, ring = self->ring[0];
     243         [ #  # ]:          0 :                 self->tx_rings > i; ++i, ring = self->ring[i]) {
     244                 :          0 :                 self->aq_hw_ops->hw_ring_tx_stop(self->aq_hw,
     245                 :            :                                                  &ring[AQ_VEC_TX_ID]);
     246                 :            : 
     247                 :          0 :                 self->aq_hw_ops->hw_ring_rx_stop(self->aq_hw,
     248                 :            :                                                  &ring[AQ_VEC_RX_ID]);
     249                 :            :         }
     250                 :            : 
     251                 :          0 :         napi_disable(&self->napi);
     252                 :          0 : }
     253                 :            : 
     254                 :          0 : void aq_vec_deinit(struct aq_vec_s *self)
     255                 :            : {
     256                 :          0 :         struct aq_ring_s *ring = NULL;
     257                 :          0 :         unsigned int i = 0U;
     258                 :            : 
     259         [ #  # ]:          0 :         if (!self)
     260                 :          0 :                 goto err_exit;
     261                 :            : 
     262                 :          0 :         for (i = 0U, ring = self->ring[0];
     263         [ #  # ]:          0 :                 self->tx_rings > i; ++i, ring = self->ring[i]) {
     264                 :          0 :                 aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
     265                 :          0 :                 aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]);
     266                 :            :         }
     267                 :            : 
     268                 :          0 : err_exit:;
     269                 :          0 : }
     270                 :            : 
     271                 :          0 : void aq_vec_free(struct aq_vec_s *self)
     272                 :            : {
     273                 :          0 :         struct aq_ring_s *ring = NULL;
     274                 :          0 :         unsigned int i = 0U;
     275                 :            : 
     276         [ #  # ]:          0 :         if (!self)
     277                 :          0 :                 goto err_exit;
     278                 :            : 
     279                 :          0 :         for (i = 0U, ring = self->ring[0];
     280         [ #  # ]:          0 :                 self->tx_rings > i; ++i, ring = self->ring[i]) {
     281                 :          0 :                 aq_ring_free(&ring[AQ_VEC_TX_ID]);
     282                 :          0 :                 aq_ring_free(&ring[AQ_VEC_RX_ID]);
     283                 :            :         }
     284                 :            : 
     285                 :          0 :         netif_napi_del(&self->napi);
     286                 :            : 
     287                 :          0 :         kfree(self);
     288                 :            : 
     289                 :          0 : err_exit:;
     290                 :          0 : }
     291                 :            : 
     292                 :          0 : irqreturn_t aq_vec_isr(int irq, void *private)
     293                 :            : {
     294                 :          0 :         struct aq_vec_s *self = private;
     295                 :          0 :         int err = 0;
     296                 :            : 
     297         [ #  # ]:          0 :         if (!self) {
     298                 :          0 :                 err = -EINVAL;
     299                 :          0 :                 goto err_exit;
     300                 :            :         }
     301                 :          0 :         napi_schedule(&self->napi);
     302                 :            : 
     303                 :          0 : err_exit:
     304                 :          0 :         return err >= 0 ? IRQ_HANDLED : IRQ_NONE;
     305                 :            : }
     306                 :            : 
     307                 :        307 : irqreturn_t aq_vec_isr_legacy(int irq, void *private)
     308                 :            : {
     309                 :        307 :         struct aq_vec_s *self = private;
     310                 :        307 :         u64 irq_mask = 0U;
     311                 :        307 :         int err;
     312                 :            : 
     313         [ +  - ]:        307 :         if (!self)
     314                 :            :                 return IRQ_NONE;
     315                 :        307 :         err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask);
     316         [ +  - ]:        307 :         if (err < 0)
     317                 :            :                 return IRQ_NONE;
     318                 :            : 
     319         [ +  + ]:        307 :         if (irq_mask) {
     320                 :        292 :                 self->aq_hw_ops->hw_irq_disable(self->aq_hw,
     321                 :        292 :                               1U << self->aq_ring_param.vec_idx);
     322                 :        292 :                 napi_schedule(&self->napi);
     323                 :            :         } else {
     324                 :         15 :                 self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U);
     325                 :         15 :                 return IRQ_NONE;
     326                 :            :         }
     327                 :            : 
     328                 :        292 :         return IRQ_HANDLED;
     329                 :            : }
     330                 :            : 
     331                 :         33 : cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self)
     332                 :            : {
     333                 :         33 :         return &self->aq_ring_param.affinity_mask;
     334                 :            : }
     335                 :            : 
     336                 :          0 : void aq_vec_add_stats(struct aq_vec_s *self,
     337                 :            :                       struct aq_ring_stats_rx_s *stats_rx,
     338                 :            :                       struct aq_ring_stats_tx_s *stats_tx)
     339                 :            : {
     340                 :          0 :         struct aq_ring_s *ring = NULL;
     341                 :          0 :         unsigned int r = 0U;
     342                 :            : 
     343                 :          0 :         for (r = 0U, ring = self->ring[0];
     344         [ #  # ]:          0 :                 self->tx_rings > r; ++r, ring = self->ring[r]) {
     345                 :          0 :                 struct aq_ring_stats_tx_s *tx = &ring[AQ_VEC_TX_ID].stats.tx;
     346                 :          0 :                 struct aq_ring_stats_rx_s *rx = &ring[AQ_VEC_RX_ID].stats.rx;
     347                 :            : 
     348                 :          0 :                 stats_rx->packets += rx->packets;
     349                 :          0 :                 stats_rx->bytes += rx->bytes;
     350                 :          0 :                 stats_rx->errors += rx->errors;
     351                 :          0 :                 stats_rx->jumbo_packets += rx->jumbo_packets;
     352                 :          0 :                 stats_rx->lro_packets += rx->lro_packets;
     353                 :          0 :                 stats_rx->pg_losts += rx->pg_losts;
     354                 :          0 :                 stats_rx->pg_flips += rx->pg_flips;
     355                 :          0 :                 stats_rx->pg_reuses += rx->pg_reuses;
     356                 :            : 
     357                 :          0 :                 stats_tx->packets += tx->packets;
     358                 :          0 :                 stats_tx->bytes += tx->bytes;
     359                 :          0 :                 stats_tx->errors += tx->errors;
     360                 :          0 :                 stats_tx->queue_restarts += tx->queue_restarts;
     361                 :            :         }
     362                 :          0 : }
     363                 :            : 
     364                 :          0 : int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count)
     365                 :            : {
     366                 :          0 :         struct aq_ring_stats_rx_s stats_rx;
     367                 :          0 :         struct aq_ring_stats_tx_s stats_tx;
     368                 :          0 :         unsigned int count = 0U;
     369                 :            : 
     370                 :          0 :         memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s));
     371                 :          0 :         memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s));
     372                 :          0 :         aq_vec_add_stats(self, &stats_rx, &stats_tx);
     373                 :            : 
     374                 :            :         /* This data should mimic aq_ethtool_queue_stat_names structure
     375                 :            :          */
     376                 :          0 :         data[count] += stats_rx.packets;
     377                 :          0 :         data[++count] += stats_tx.packets;
     378                 :          0 :         data[++count] += stats_tx.queue_restarts;
     379                 :          0 :         data[++count] += stats_rx.jumbo_packets;
     380                 :          0 :         data[++count] += stats_rx.lro_packets;
     381                 :          0 :         data[++count] += stats_rx.errors;
     382                 :            : 
     383         [ #  # ]:          0 :         if (p_count)
     384                 :          0 :                 *p_count = ++count;
     385                 :            : 
     386                 :          0 :         return 0;
     387                 :            : }

Generated by: LCOV version 1.14