igc_tsn.c (6539B)
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}