linux/drivers/net/ethernet/intel/igc/igc_tsn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c)  2019 Intel Corporation */
   3
   4#include "igc.h"
   5#include "igc_tsn.h"
   6
   7static bool is_any_launchtime(struct igc_adapter *adapter)
   8{
   9        int i;
  10
  11        for (i = 0; i < adapter->num_tx_queues; i++) {
  12                struct igc_ring *ring = adapter->tx_ring[i];
  13
  14                if (ring->launchtime_enable)
  15                        return true;
  16        }
  17
  18        return false;
  19}
  20
  21/* Returns the TSN specific registers to their default values after
  22 * TSN offloading is disabled.
  23 */
  24static int igc_tsn_disable_offload(struct igc_adapter *adapter)
  25{
  26        struct igc_hw *hw = &adapter->hw;
  27        u32 tqavctrl;
  28        int i;
  29
  30        if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED))
  31                return 0;
  32
  33        adapter->cycle_time = 0;
  34
  35        wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
  36        wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
  37
  38        tqavctrl = rd32(IGC_TQAVCTRL);
  39        tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
  40                      IGC_TQAVCTRL_ENHANCED_QAV);
  41        wr32(IGC_TQAVCTRL, tqavctrl);
  42
  43        for (i = 0; i < adapter->num_tx_queues; i++) {
  44                struct igc_ring *ring = adapter->tx_ring[i];
  45
  46                ring->start_time = 0;
  47                ring->end_time = 0;
  48                ring->launchtime_enable = false;
  49
  50                wr32(IGC_TXQCTL(i), 0);
  51                wr32(IGC_STQT(i), 0);
  52                wr32(IGC_ENDQT(i), NSEC_PER_SEC);
  53        }
  54
  55        wr32(IGC_QBVCYCLET_S, NSEC_PER_SEC);
  56        wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
  57
  58        adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
  59
  60        return 0;
  61}
  62
  63static int igc_tsn_enable_offload(struct igc_adapter *adapter)
  64{
  65        struct igc_hw *hw = &adapter->hw;
  66        u32 tqavctrl, baset_l, baset_h;
  67        u32 sec, nsec, cycle;
  68        ktime_t base_time, systim;
  69        int i;
  70
  71        if (adapter->flags & IGC_FLAG_TSN_QBV_ENABLED)
  72                return 0;
  73
  74        cycle = adapter->cycle_time;
  75        base_time = adapter->base_time;
  76
  77        wr32(IGC_TSAUXC, 0);
  78        wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
  79        wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
  80
  81        tqavctrl = rd32(IGC_TQAVCTRL);
  82        tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
  83        wr32(IGC_TQAVCTRL, tqavctrl);
  84
  85        wr32(IGC_QBVCYCLET_S, cycle);
  86        wr32(IGC_QBVCYCLET, cycle);
  87
  88        for (i = 0; i < adapter->num_tx_queues; i++) {
  89                struct igc_ring *ring = adapter->tx_ring[i];
  90                u32 txqctl = 0;
  91
  92                wr32(IGC_STQT(i), ring->start_time);
  93                wr32(IGC_ENDQT(i), ring->end_time);
  94
  95                if (adapter->base_time) {
  96                        /* If we have a base_time we are in "taprio"
  97                         * mode and we need to be strict about the
  98                         * cycles: only transmit a packet if it can be
  99                         * completed during that cycle.
 100                         */
 101                        txqctl |= IGC_TXQCTL_STRICT_CYCLE |
 102                                IGC_TXQCTL_STRICT_END;
 103                }
 104
 105                if (ring->launchtime_enable)
 106                        txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
 107
 108                wr32(IGC_TXQCTL(i), txqctl);
 109        }
 110
 111        nsec = rd32(IGC_SYSTIML);
 112        sec = rd32(IGC_SYSTIMH);
 113
 114        systim = ktime_set(sec, nsec);
 115
 116        if (ktime_compare(systim, base_time) > 0) {
 117                s64 n;
 118
 119                n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
 120                base_time = ktime_add_ns(base_time, (n + 1) * cycle);
 121        }
 122
 123        baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
 124
 125        wr32(IGC_BASET_H, baset_h);
 126        wr32(IGC_BASET_L, baset_l);
 127
 128        adapter->flags |= IGC_FLAG_TSN_QBV_ENABLED;
 129
 130        return 0;
 131}
 132
 133int igc_tsn_offload_apply(struct igc_adapter *adapter)
 134{
 135        bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter);
 136
 137        if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled)
 138                return 0;
 139
 140        if (!is_any_enabled) {
 141                int err = igc_tsn_disable_offload(adapter);
 142
 143                if (err < 0)
 144                        return err;
 145
 146                /* The BASET registers aren't cleared when writing
 147                 * into them, force a reset if the interface is
 148                 * running.
 149                 */
 150                if (netif_running(adapter->netdev))
 151                        schedule_work(&adapter->reset_task);
 152
 153                return 0;
 154        }
 155
 156        return igc_tsn_enable_offload(adapter);
 157}
 158