1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2015-2020 3 */ 4 5 #include "txgbe_type.h" 6 #include "txgbe_hw.h" 7 #include "txgbe_dcb.h" 8 #include "txgbe_dcb_hw.h" 9 10 /** 11 * txgbe_pfc_enable - Enable flow control 12 * @hw: pointer to hardware structure 13 * @tc_num: traffic class number 14 * Enable flow control according to the current settings. 15 */ 16 int 17 txgbe_dcb_pfc_enable(struct txgbe_hw *hw, uint8_t tc_num) 18 { 19 int ret_val = 0; 20 uint32_t mflcn_reg, fccfg_reg; 21 uint32_t pause_time; 22 uint32_t fcrtl, fcrth; 23 uint8_t i; 24 uint8_t nb_rx_en; 25 26 /* Validate the water mark configuration */ 27 if (!hw->fc.pause_time) { 28 ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS; 29 goto out; 30 } 31 32 /* Low water mark of zero causes XOFF floods */ 33 if (hw->fc.current_mode & txgbe_fc_tx_pause) { 34 /* High/Low water can not be 0 */ 35 if (!hw->fc.high_water[tc_num] || 36 !hw->fc.low_water[tc_num]) { 37 PMD_INIT_LOG(ERR, "Invalid water mark configuration"); 38 ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS; 39 goto out; 40 } 41 42 if (hw->fc.low_water[tc_num] >= hw->fc.high_water[tc_num]) { 43 PMD_INIT_LOG(ERR, "Invalid water mark configuration"); 44 ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS; 45 goto out; 46 } 47 } 48 /* Negotiate the fc mode to use */ 49 txgbe_fc_autoneg(hw); 50 51 /* Disable any previous flow control settings */ 52 mflcn_reg = rd32(hw, TXGBE_RXFCCFG); 53 mflcn_reg &= ~(TXGBE_RXFCCFG_FC | TXGBE_RXFCCFG_PFC); 54 55 fccfg_reg = rd32(hw, TXGBE_TXFCCFG); 56 fccfg_reg &= ~(TXGBE_TXFCCFG_FC | TXGBE_TXFCCFG_PFC); 57 58 switch (hw->fc.current_mode) { 59 case txgbe_fc_none: 60 /* 61 * If the count of enabled RX Priority Flow control > 1, 62 * and the TX pause can not be disabled 63 */ 64 nb_rx_en = 0; 65 for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { 66 uint32_t reg = rd32(hw, TXGBE_FCWTRHI(i)); 67 if (reg & TXGBE_FCWTRHI_XOFF) 68 nb_rx_en++; 69 } 70 if (nb_rx_en > 1) 71 fccfg_reg |= TXGBE_TXFCCFG_PFC; 72 break; 73 case txgbe_fc_rx_pause: 74 /* 75 * Rx Flow control is enabled and Tx Flow control is 76 * disabled by software override. Since there really 77 * isn't a way to advertise that we are capable of RX 78 * Pause ONLY, we will advertise that we support both 79 * symmetric and asymmetric Rx PAUSE. Later, we will 80 * disable the adapter's ability to send PAUSE frames. 81 */ 82 mflcn_reg |= TXGBE_RXFCCFG_PFC; 83 /* 84 * If the count of enabled RX Priority Flow control > 1, 85 * and the TX pause can not be disabled 86 */ 87 nb_rx_en = 0; 88 for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { 89 uint32_t reg = rd32(hw, TXGBE_FCWTRHI(i)); 90 if (reg & TXGBE_FCWTRHI_XOFF) 91 nb_rx_en++; 92 } 93 if (nb_rx_en > 1) 94 fccfg_reg |= TXGBE_TXFCCFG_PFC; 95 break; 96 case txgbe_fc_tx_pause: 97 /* 98 * Tx Flow control is enabled, and Rx Flow control is 99 * disabled by software override. 100 */ 101 fccfg_reg |= TXGBE_TXFCCFG_PFC; 102 break; 103 case txgbe_fc_full: 104 /* Flow control (both Rx and Tx) is enabled by SW override. */ 105 mflcn_reg |= TXGBE_RXFCCFG_PFC; 106 fccfg_reg |= TXGBE_TXFCCFG_PFC; 107 break; 108 default: 109 PMD_DRV_LOG(DEBUG, "Flow control param set incorrectly"); 110 ret_val = TXGBE_ERR_CONFIG; 111 goto out; 112 } 113 114 /* Set 802.3x based flow control settings. */ 115 wr32(hw, TXGBE_RXFCCFG, mflcn_reg); 116 wr32(hw, TXGBE_TXFCCFG, fccfg_reg); 117 118 /* Set up and enable Rx high/low water mark thresholds, enable XON. */ 119 if ((hw->fc.current_mode & txgbe_fc_tx_pause) && 120 hw->fc.high_water[tc_num]) { 121 fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[tc_num]) | 122 TXGBE_FCWTRLO_XON; 123 fcrth = TXGBE_FCWTRHI_TH(hw->fc.high_water[tc_num]) | 124 TXGBE_FCWTRHI_XOFF; 125 } else { 126 /* 127 * In order to prevent Tx hangs when the internal Tx 128 * switch is enabled we must set the high water mark 129 * to the maximum FCRTH value. This allows the Tx 130 * switch to function even under heavy Rx workloads. 131 */ 132 fcrtl = 0; 133 fcrth = rd32(hw, TXGBE_PBRXSIZE(tc_num)) - 32; 134 } 135 wr32(hw, TXGBE_FCWTRLO(tc_num), fcrtl); 136 wr32(hw, TXGBE_FCWTRHI(tc_num), fcrth); 137 138 /* Configure pause time (2 TCs per register) */ 139 pause_time = TXGBE_RXFCFSH_TIME(hw->fc.pause_time); 140 for (i = 0; i < (TXGBE_DCB_TC_MAX / 2); i++) 141 wr32(hw, TXGBE_FCXOFFTM(i), pause_time * 0x00010001); 142 143 /* Configure flow control refresh threshold value */ 144 wr32(hw, TXGBE_RXFCRFSH, pause_time / 2); 145 146 out: 147 return ret_val; 148 } 149 150 /** 151 * txgbe_dcb_calculate_tc_credits_cee - Calculates traffic class credits 152 * @hw: pointer to hardware structure 153 * @dcb_config: Struct containing DCB settings 154 * @max_frame_size: Maximum frame size 155 * @direction: Configuring either Tx or Rx 156 * 157 * This function calculates the credits allocated to each traffic class. 158 * It should be called only after the rules are checked by 159 * txgbe_dcb_check_config_cee(). 160 */ 161 s32 txgbe_dcb_calculate_tc_credits_cee(struct txgbe_hw *hw, 162 struct txgbe_dcb_config *dcb_config, 163 u32 max_frame_size, u8 direction) 164 { 165 struct txgbe_dcb_tc_path *p; 166 u32 min_multiplier = 0; 167 u16 min_percent = 100; 168 s32 ret_val = 0; 169 /* Initialization values default for Tx settings */ 170 u32 min_credit = 0; 171 u32 credit_refill = 0; 172 u32 credit_max = 0; 173 u16 link_percentage = 0; 174 u8 bw_percent = 0; 175 u8 i; 176 177 UNREFERENCED_PARAMETER(hw); 178 179 if (dcb_config == NULL) { 180 ret_val = TXGBE_ERR_CONFIG; 181 goto out; 182 } 183 184 min_credit = ((max_frame_size / 2) + TXGBE_DCB_CREDIT_QUANTUM - 1) / 185 TXGBE_DCB_CREDIT_QUANTUM; 186 187 /* Find smallest link percentage */ 188 for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { 189 p = &dcb_config->tc_config[i].path[direction]; 190 bw_percent = dcb_config->bw_percentage[p->bwg_id][direction]; 191 link_percentage = p->bwg_percent; 192 193 link_percentage = (link_percentage * bw_percent) / 100; 194 195 if (link_percentage && link_percentage < min_percent) 196 min_percent = link_percentage; 197 } 198 199 /* 200 * The ratio between traffic classes will control the bandwidth 201 * percentages seen on the wire. To calculate this ratio we use 202 * a multiplier. It is required that the refill credits must be 203 * larger than the max frame size so here we find the smallest 204 * multiplier that will allow all bandwidth percentages to be 205 * greater than the max frame size. 206 */ 207 min_multiplier = (min_credit / min_percent) + 1; 208 209 /* Find out the link percentage for each TC first */ 210 for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { 211 p = &dcb_config->tc_config[i].path[direction]; 212 bw_percent = dcb_config->bw_percentage[p->bwg_id][direction]; 213 214 link_percentage = p->bwg_percent; 215 /* Must be careful of integer division for very small nums */ 216 link_percentage = (link_percentage * bw_percent) / 100; 217 if (p->bwg_percent > 0 && link_percentage == 0) 218 link_percentage = 1; 219 220 /* Save link_percentage for reference */ 221 p->link_percent = (u8)link_percentage; 222 223 /* Calculate credit refill ratio using multiplier */ 224 credit_refill = min(link_percentage * min_multiplier, 225 (u32)TXGBE_DCB_MAX_CREDIT_REFILL); 226 227 /* Refill at least minimum credit */ 228 if (credit_refill < min_credit) 229 credit_refill = min_credit; 230 231 p->data_credits_refill = (u16)credit_refill; 232 233 /* Calculate maximum credit for the TC */ 234 credit_max = (link_percentage * TXGBE_DCB_MAX_CREDIT) / 100; 235 236 /* 237 * Adjustment based on rule checking, if the percentage 238 * of a TC is too small, the maximum credit may not be 239 * enough to send out a jumbo frame in data plane arbitration. 240 */ 241 if (credit_max < min_credit) 242 credit_max = min_credit; 243 244 if (direction == TXGBE_DCB_TX_CONFIG) { 245 dcb_config->tc_config[i].desc_credits_max = 246 (u16)credit_max; 247 } 248 249 p->data_credits_max = (u16)credit_max; 250 } 251 252 out: 253 return ret_val; 254 } 255 256 /** 257 * txgbe_dcb_unpack_pfc_cee - Unpack dcb_config PFC info 258 * @cfg: dcb configuration to unpack into hardware consumable fields 259 * @map: user priority to traffic class map 260 * @pfc_up: u8 to store user priority PFC bitmask 261 * 262 * This unpacks the dcb configuration PFC info which is stored per 263 * traffic class into a 8bit user priority bitmask that can be 264 * consumed by hardware routines. The priority to tc map must be 265 * updated before calling this routine to use current up-to maps. 266 */ 267 void txgbe_dcb_unpack_pfc_cee(struct txgbe_dcb_config *cfg, u8 *map, u8 *pfc_up) 268 { 269 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 270 int up; 271 272 /* 273 * If the TC for this user priority has PFC enabled then set the 274 * matching bit in 'pfc_up' to reflect that PFC is enabled. 275 */ 276 for (*pfc_up = 0, up = 0; up < TXGBE_DCB_UP_MAX; up++) { 277 if (tc_config[map[up]].pfc != txgbe_dcb_pfc_disabled) 278 *pfc_up |= 1 << up; 279 } 280 } 281 282 void txgbe_dcb_unpack_refill_cee(struct txgbe_dcb_config *cfg, int direction, 283 u16 *refill) 284 { 285 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 286 int tc; 287 288 for (tc = 0; tc < TXGBE_DCB_TC_MAX; tc++) 289 refill[tc] = tc_config[tc].path[direction].data_credits_refill; 290 } 291 292 void txgbe_dcb_unpack_max_cee(struct txgbe_dcb_config *cfg, u16 *max) 293 { 294 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 295 int tc; 296 297 for (tc = 0; tc < TXGBE_DCB_TC_MAX; tc++) 298 max[tc] = tc_config[tc].desc_credits_max; 299 } 300 301 void txgbe_dcb_unpack_bwgid_cee(struct txgbe_dcb_config *cfg, int direction, 302 u8 *bwgid) 303 { 304 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 305 int tc; 306 307 for (tc = 0; tc < TXGBE_DCB_TC_MAX; tc++) 308 bwgid[tc] = tc_config[tc].path[direction].bwg_id; 309 } 310 311 void txgbe_dcb_unpack_tsa_cee(struct txgbe_dcb_config *cfg, int direction, 312 u8 *tsa) 313 { 314 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 315 int tc; 316 317 for (tc = 0; tc < TXGBE_DCB_TC_MAX; tc++) 318 tsa[tc] = tc_config[tc].path[direction].tsa; 319 } 320 321 u8 txgbe_dcb_get_tc_from_up(struct txgbe_dcb_config *cfg, int direction, u8 up) 322 { 323 struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; 324 u8 prio_mask = 1 << up; 325 u8 tc = cfg->num_tcs.pg_tcs; 326 327 /* If tc is 0 then DCB is likely not enabled or supported */ 328 if (!tc) 329 goto out; 330 331 /* 332 * Test from maximum TC to 1 and report the first match we find. If 333 * we find no match we can assume that the TC is 0 since the TC must 334 * be set for all user priorities 335 */ 336 for (tc--; tc; tc--) { 337 if (prio_mask & tc_config[tc].path[direction].up_to_tc_bitmap) 338 break; 339 } 340 out: 341 return tc; 342 } 343 344 void txgbe_dcb_unpack_map_cee(struct txgbe_dcb_config *cfg, int direction, 345 u8 *map) 346 { 347 u8 up; 348 349 for (up = 0; up < TXGBE_DCB_UP_MAX; up++) 350 map[up] = txgbe_dcb_get_tc_from_up(cfg, direction, up); 351 } 352 353 /* Helper routines to abstract HW specifics from DCB netlink ops */ 354 s32 txgbe_dcb_config_pfc(struct txgbe_hw *hw, u8 pfc_en, u8 *map) 355 { 356 int ret = TXGBE_ERR_PARAM; 357 ret = txgbe_dcb_config_pfc_raptor(hw, pfc_en, map); 358 return ret; 359 } 360 361