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->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 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 if (adapter->base_time) { 144 /* If we have a base_time we are in "taprio" 145 * mode and we need to be strict about the 146 * cycles: only transmit a packet if it can be 147 * completed during that cycle. 148 */ 149 txqctl |= IGC_TXQCTL_STRICT_CYCLE | 150 IGC_TXQCTL_STRICT_END; 151 } 152 153 if (ring->launchtime_enable) 154 txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT; 155 156 /* Skip configuring CBS for Q2 and Q3 */ 157 if (i > 1) 158 goto skip_cbs; 159 160 if (ring->cbs_enable) { 161 if (i == 0) 162 txqctl |= IGC_TXQCTL_QAV_SEL_CBS0; 163 else 164 txqctl |= IGC_TXQCTL_QAV_SEL_CBS1; 165 166 /* According to i225 datasheet section 7.5.2.7, we 167 * should set the 'idleSlope' field from TQAVCC 168 * register following the equation: 169 * 170 * value = link-speed 0x7736 * BW * 0.2 171 * ---------- * ----------------- (E1) 172 * 100Mbps 2.5 173 * 174 * Note that 'link-speed' is in Mbps. 175 * 176 * 'BW' is the percentage bandwidth out of full 177 * link speed which can be found with the 178 * following equation. Note that idleSlope here 179 * is the parameter from this function 180 * which is in kbps. 181 * 182 * BW = idleSlope 183 * ----------------- (E2) 184 * link-speed * 1000 185 * 186 * That said, we can come up with a generic 187 * equation to calculate the value we should set 188 * it TQAVCC register by replacing 'BW' in E1 by E2. 189 * The resulting equation is: 190 * 191 * value = link-speed * 0x7736 * idleSlope * 0.2 192 * ------------------------------------- (E3) 193 * 100 * 2.5 * link-speed * 1000 194 * 195 * 'link-speed' is present in both sides of the 196 * fraction so it is canceled out. The final 197 * equation is the following: 198 * 199 * value = idleSlope * 61036 200 * ----------------- (E4) 201 * 2500000 202 * 203 * NOTE: For i225, given the above, we can see 204 * that idleslope is represented in 205 * 40.959433 kbps units by the value at 206 * the TQAVCC register (2.5Gbps / 61036), 207 * which reduces the granularity for 208 * idleslope increments. 209 * 210 * In i225 controller, the sendSlope and loCredit 211 * parameters from CBS are not configurable 212 * by software so we don't do any 213 * 'controller configuration' in respect to 214 * these parameters. 215 */ 216 cbs_value = DIV_ROUND_UP_ULL(ring->idleslope 217 * 61036ULL, 2500000); 218 219 tqavcc = rd32(IGC_TQAVCC(i)); 220 tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK; 221 tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS; 222 wr32(IGC_TQAVCC(i), tqavcc); 223 224 wr32(IGC_TQAVHC(i), 225 0x80000000 + ring->hicredit * 0x7735); 226 } else { 227 /* Disable any CBS for the queue */ 228 txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK); 229 230 /* Set idleSlope to zero. */ 231 tqavcc = rd32(IGC_TQAVCC(i)); 232 tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK | 233 IGC_TQAVCC_KEEP_CREDITS); 234 wr32(IGC_TQAVCC(i), tqavcc); 235 236 /* Set hiCredit to zero. */ 237 wr32(IGC_TQAVHC(i), 0); 238 } 239 skip_cbs: 240 wr32(IGC_TXQCTL(i), txqctl); 241 } 242 243 nsec = rd32(IGC_SYSTIML); 244 sec = rd32(IGC_SYSTIMH); 245 246 systim = ktime_set(sec, nsec); 247 248 if (ktime_compare(systim, base_time) > 0) { 249 s64 n; 250 251 n = div64_s64(ktime_sub_ns(systim, base_time), cycle); 252 base_time = ktime_add_ns(base_time, (n + 1) * cycle); 253 } 254 255 baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l); 256 257 wr32(IGC_BASET_H, baset_h); 258 wr32(IGC_BASET_L, baset_l); 259 260 return 0; 261 } 262 263 int igc_tsn_reset(struct igc_adapter *adapter) 264 { 265 unsigned int new_flags; 266 int err = 0; 267 268 new_flags = igc_tsn_new_flags(adapter); 269 270 if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED)) 271 return igc_tsn_disable_offload(adapter); 272 273 err = igc_tsn_enable_offload(adapter); 274 if (err < 0) 275 return err; 276 277 adapter->flags = new_flags; 278 279 return err; 280 } 281 282 int igc_tsn_offload_apply(struct igc_adapter *adapter) 283 { 284 int err; 285 286 if (netif_running(adapter->netdev)) { 287 schedule_work(&adapter->reset_task); 288 return 0; 289 } 290 291 err = igc_tsn_enable_offload(adapter); 292 if (err < 0) 293 return err; 294 295 adapter->flags = igc_tsn_new_flags(adapter); 296 return 0; 297 } 298