0001
0002
0003
0004 #include "igc.h"
0005 #include "igc_tsn.h"
0006
0007 static bool is_any_launchtime(struct igc_adapter *adapter)
0008 {
0009 int i;
0010
0011 for (i = 0; i < adapter->num_tx_queues; i++) {
0012 struct igc_ring *ring = adapter->tx_ring[i];
0013
0014 if (ring->launchtime_enable)
0015 return true;
0016 }
0017
0018 return false;
0019 }
0020
0021 static bool is_cbs_enabled(struct igc_adapter *adapter)
0022 {
0023 int i;
0024
0025 for (i = 0; i < adapter->num_tx_queues; i++) {
0026 struct igc_ring *ring = adapter->tx_ring[i];
0027
0028 if (ring->cbs_enable)
0029 return true;
0030 }
0031
0032 return false;
0033 }
0034
0035 static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
0036 {
0037 unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
0038
0039 if (adapter->base_time)
0040 new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
0041
0042 if (is_any_launchtime(adapter))
0043 new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
0044
0045 if (is_cbs_enabled(adapter))
0046 new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
0047
0048 return new_flags;
0049 }
0050
0051
0052
0053
0054 static int igc_tsn_disable_offload(struct igc_adapter *adapter)
0055 {
0056 struct igc_hw *hw = &adapter->hw;
0057 u32 tqavctrl;
0058 int i;
0059
0060 wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
0061 wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
0062
0063 tqavctrl = rd32(IGC_TQAVCTRL);
0064 tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
0065 IGC_TQAVCTRL_ENHANCED_QAV);
0066 wr32(IGC_TQAVCTRL, tqavctrl);
0067
0068 for (i = 0; i < adapter->num_tx_queues; i++) {
0069 wr32(IGC_TXQCTL(i), 0);
0070 wr32(IGC_STQT(i), 0);
0071 wr32(IGC_ENDQT(i), NSEC_PER_SEC);
0072 }
0073
0074 wr32(IGC_QBVCYCLET_S, 0);
0075 wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
0076
0077 adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
0078
0079 return 0;
0080 }
0081
0082 static int igc_tsn_enable_offload(struct igc_adapter *adapter)
0083 {
0084 struct igc_hw *hw = &adapter->hw;
0085 u32 tqavctrl, baset_l, baset_h;
0086 u32 sec, nsec, cycle;
0087 ktime_t base_time, systim;
0088 int i;
0089
0090 cycle = adapter->cycle_time;
0091 base_time = adapter->base_time;
0092
0093 wr32(IGC_TSAUXC, 0);
0094 wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
0095 wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
0096
0097 tqavctrl = rd32(IGC_TQAVCTRL);
0098 tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
0099 wr32(IGC_TQAVCTRL, tqavctrl);
0100
0101 wr32(IGC_QBVCYCLET_S, cycle);
0102 wr32(IGC_QBVCYCLET, cycle);
0103
0104 for (i = 0; i < adapter->num_tx_queues; i++) {
0105 struct igc_ring *ring = adapter->tx_ring[i];
0106 u32 txqctl = 0;
0107 u16 cbs_value;
0108 u32 tqavcc;
0109
0110 wr32(IGC_STQT(i), ring->start_time);
0111 wr32(IGC_ENDQT(i), ring->end_time);
0112
0113 if (adapter->base_time) {
0114
0115
0116
0117
0118
0119 txqctl |= IGC_TXQCTL_STRICT_CYCLE |
0120 IGC_TXQCTL_STRICT_END;
0121 }
0122
0123 if (ring->launchtime_enable)
0124 txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
0125
0126
0127 if (i > 1)
0128 goto skip_cbs;
0129
0130 if (ring->cbs_enable) {
0131 if (i == 0)
0132 txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
0133 else
0134 txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
0187 * 61036ULL, 2500000);
0188
0189 tqavcc = rd32(IGC_TQAVCC(i));
0190 tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
0191 tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
0192 wr32(IGC_TQAVCC(i), tqavcc);
0193
0194 wr32(IGC_TQAVHC(i),
0195 0x80000000 + ring->hicredit * 0x7735);
0196 } else {
0197
0198 txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
0199
0200
0201 tqavcc = rd32(IGC_TQAVCC(i));
0202 tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
0203 IGC_TQAVCC_KEEP_CREDITS);
0204 wr32(IGC_TQAVCC(i), tqavcc);
0205
0206
0207 wr32(IGC_TQAVHC(i), 0);
0208 }
0209 skip_cbs:
0210 wr32(IGC_TXQCTL(i), txqctl);
0211 }
0212
0213 nsec = rd32(IGC_SYSTIML);
0214 sec = rd32(IGC_SYSTIMH);
0215
0216 systim = ktime_set(sec, nsec);
0217
0218 if (ktime_compare(systim, base_time) > 0) {
0219 s64 n;
0220
0221 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
0222 base_time = ktime_add_ns(base_time, (n + 1) * cycle);
0223 }
0224
0225 baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
0226
0227 wr32(IGC_BASET_H, baset_h);
0228 wr32(IGC_BASET_L, baset_l);
0229
0230 return 0;
0231 }
0232
0233 int igc_tsn_reset(struct igc_adapter *adapter)
0234 {
0235 unsigned int new_flags;
0236 int err = 0;
0237
0238 new_flags = igc_tsn_new_flags(adapter);
0239
0240 if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
0241 return igc_tsn_disable_offload(adapter);
0242
0243 err = igc_tsn_enable_offload(adapter);
0244 if (err < 0)
0245 return err;
0246
0247 adapter->flags = new_flags;
0248
0249 return err;
0250 }
0251
0252 int igc_tsn_offload_apply(struct igc_adapter *adapter)
0253 {
0254 int err;
0255
0256 if (netif_running(adapter->netdev)) {
0257 schedule_work(&adapter->reset_task);
0258 return 0;
0259 }
0260
0261 err = igc_tsn_enable_offload(adapter);
0262 if (err < 0)
0263 return err;
0264
0265 adapter->flags = igc_tsn_new_flags(adapter);
0266 return 0;
0267 }