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
  21static bool is_cbs_enabled(struct igc_adapter *adapter)
  22{
  23        int i;
  24
  25        for (i = 0; i < adapter->num_tx_queues; i++) {
  26                struct igc_ring *ring = adapter->tx_ring[i];
  27
  28                if (ring->cbs_enable)
  29                        return true;
  30        }
  31
  32        return false;
  33}
  34
  35static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
  36{
  37        unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
  38
  39        if (adapter->base_time)
  40                new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
  41
  42        if (is_any_launchtime(adapter))
  43                new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
  44
  45        if (is_cbs_enabled(adapter))
  46                new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
  47
  48        return new_flags;
  49}
  50
  51/* Returns the TSN specific registers to their default values after
  52 * the adapter is reset.
  53 */
  54static int igc_tsn_disable_offload(struct igc_adapter *adapter)
  55{
  56        struct igc_hw *hw = &adapter->hw;
  57        u32 tqavctrl;
  58        int i;
  59
  60        wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
  61        wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
  62
  63        tqavctrl = rd32(IGC_TQAVCTRL);
  64        tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
  65                      IGC_TQAVCTRL_ENHANCED_QAV);
  66        wr32(IGC_TQAVCTRL, tqavctrl);
  67
  68        for (i = 0; i < adapter->num_tx_queues; i++) {
  69                wr32(IGC_TXQCTL(i), 0);
  70                wr32(IGC_STQT(i), 0);
  71                wr32(IGC_ENDQT(i), NSEC_PER_SEC);
  72        }
  73
  74        wr32(IGC_QBVCYCLET_S, 0);
  75        wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
  76
  77        adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
  78
  79        return 0;
  80}
  81
  82static int igc_tsn_enable_offload(struct igc_adapter *adapter)
  83{
  84        struct igc_hw *hw = &adapter->hw;
  85        u32 tqavctrl, baset_l, baset_h;
  86        u32 sec, nsec, cycle;
  87        ktime_t base_time, systim;
  88        int i;
  89
  90        cycle = adapter->cycle_time;
  91        base_time = adapter->base_time;
  92
  93        wr32(IGC_TSAUXC, 0);
  94        wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
  95        wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
  96
  97        tqavctrl = rd32(IGC_TQAVCTRL);
  98        tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
  99        wr32(IGC_TQAVCTRL, tqavctrl);
 100
 101        wr32(IGC_QBVCYCLET_S, cycle);
 102        wr32(IGC_QBVCYCLET, cycle);
 103
 104        for (i = 0; i < adapter->num_tx_queues; i++) {
 105                struct igc_ring *ring = adapter->tx_ring[i];
 106                u32 txqctl = 0;
 107                u16 cbs_value;
 108                u32 tqavcc;
 109
 110                wr32(IGC_STQT(i), ring->start_time);
 111                wr32(IGC_ENDQT(i), ring->end_time);
 112
 113                if (adapter->base_time) {
 114                        /* If we have a base_time we are in "taprio"
 115                         * mode and we need to be strict about the
 116                         * cycles: only transmit a packet if it can be
 117                         * completed during that cycle.
 118                         */
 119                        txqctl |= IGC_TXQCTL_STRICT_CYCLE |
 120                                IGC_TXQCTL_STRICT_END;
 121                }
 122
 123                if (ring->launchtime_enable)
 124                        txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
 125
 126                /* Skip configuring CBS for Q2 and Q3 */
 127                if (i > 1)
 128                        goto skip_cbs;
 129
 130                if (ring->cbs_enable) {
 131                        if (i == 0)
 132                                txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
 133                        else
 134                                txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
 135
 136                        /* According to i225 datasheet section 7.5.2.7, we
 137                         * should set the 'idleSlope' field from TQAVCC
 138                         * register following the equation:
 139                         *
 140                         * value = link-speed   0x7736 * BW * 0.2
 141                         *         ---------- *  -----------------         (E1)
 142                         *          100Mbps            2.5
 143                         *
 144                         * Note that 'link-speed' is in Mbps.
 145                         *
 146                         * 'BW' is the percentage bandwidth out of full
 147                         * link speed which can be found with the
 148                         * following equation. Note that idleSlope here
 149                         * is the parameter from this function
 150                         * which is in kbps.
 151                         *
 152                         *     BW =     idleSlope
 153                         *          -----------------                      (E2)
 154                         *          link-speed * 1000
 155                         *
 156                         * That said, we can come up with a generic
 157                         * equation to calculate the value we should set
 158                         * it TQAVCC register by replacing 'BW' in E1 by E2.
 159                         * The resulting equation is:
 160                         *
 161                         * value = link-speed * 0x7736 * idleSlope * 0.2
 162                         *         -------------------------------------   (E3)
 163                         *             100 * 2.5 * link-speed * 1000
 164                         *
 165                         * 'link-speed' is present in both sides of the
 166                         * fraction so it is canceled out. The final
 167                         * equation is the following:
 168                         *
 169                         *     value = idleSlope * 61036
 170                         *             -----------------                   (E4)
 171                         *                  2500000
 172                         *
 173                         * NOTE: For i225, given the above, we can see
 174                         *       that idleslope is represented in
 175                         *       40.959433 kbps units by the value at
 176                         *       the TQAVCC register (2.5Gbps / 61036),
 177                         *       which reduces the granularity for
 178                         *       idleslope increments.
 179                         *
 180                         * In i225 controller, the sendSlope and loCredit
 181                         * parameters from CBS are not configurable
 182                         * by software so we don't do any
 183                         * 'controller configuration' in respect to
 184                         * these parameters.
 185                         */
 186                        cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
 187                                                     * 61036ULL, 2500000);
 188
 189                        tqavcc = rd32(IGC_TQAVCC(i));
 190                        tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
 191                        tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
 192                        wr32(IGC_TQAVCC(i), tqavcc);
 193
 194                        wr32(IGC_TQAVHC(i),
 195                             0x80000000 + ring->hicredit * 0x7735);
 196                } else {
 197                        /* Disable any CBS for the queue */
 198                        txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
 199
 200                        /* Set idleSlope to zero. */
 201                        tqavcc = rd32(IGC_TQAVCC(i));
 202                        tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
 203                                    IGC_TQAVCC_KEEP_CREDITS);
 204                        wr32(IGC_TQAVCC(i), tqavcc);
 205
 206                        /* Set hiCredit to zero. */
 207                        wr32(IGC_TQAVHC(i), 0);
 208                }
 209skip_cbs:
 210                wr32(IGC_TXQCTL(i), txqctl);
 211        }
 212
 213        nsec = rd32(IGC_SYSTIML);
 214        sec = rd32(IGC_SYSTIMH);
 215
 216        systim = ktime_set(sec, nsec);
 217
 218        if (ktime_compare(systim, base_time) > 0) {
 219                s64 n;
 220
 221                n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
 222                base_time = ktime_add_ns(base_time, (n + 1) * cycle);
 223        }
 224
 225        baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
 226
 227        wr32(IGC_BASET_H, baset_h);
 228        wr32(IGC_BASET_L, baset_l);
 229
 230        return 0;
 231}
 232
 233int igc_tsn_reset(struct igc_adapter *adapter)
 234{
 235        unsigned int new_flags;
 236        int err = 0;
 237
 238        new_flags = igc_tsn_new_flags(adapter);
 239
 240        if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
 241                return igc_tsn_disable_offload(adapter);
 242
 243        err = igc_tsn_enable_offload(adapter);
 244        if (err < 0)
 245                return err;
 246
 247        adapter->flags = new_flags;
 248
 249        return err;
 250}
 251
 252int igc_tsn_offload_apply(struct igc_adapter *adapter)
 253{
 254        int err;
 255
 256        if (netif_running(adapter->netdev)) {
 257                schedule_work(&adapter->reset_task);
 258                return 0;
 259        }
 260
 261        err = igc_tsn_enable_offload(adapter);
 262        if (err < 0)
 263                return err;
 264
 265        adapter->flags = igc_tsn_new_flags(adapter);
 266        return 0;
 267}
 268