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