1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2022 Marvell. 3 */ 4 5 #include "roc_api.h" 6 #include "roc_priv.h" 7 8 static const uint8_t y_mask_val[ROC_NIX_TM_MARK_MAX][2] = { 9 [ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8}, 10 [ROC_NIX_TM_MARK_IPV4_DSCP] = {0x1, 0x2}, 11 [ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc}, 12 [ROC_NIX_TM_MARK_IPV6_DSCP] = {0x1, 0x2}, 13 [ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3}, 14 }; 15 16 static const uint8_t r_mask_val[ROC_NIX_TM_MARK_MAX][2] = { 17 [ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8}, 18 [ROC_NIX_TM_MARK_IPV4_DSCP] = {0x0, 0x3}, 19 [ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc}, 20 [ROC_NIX_TM_MARK_IPV6_DSCP] = {0x0, 0x3}, 21 [ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3}, 22 }; 23 24 static const uint8_t mark_off[ROC_NIX_TM_MARK_MAX] = { 25 [ROC_NIX_TM_MARK_VLAN_DEI] = 0x3, /* Byte 14 Bit[4:1] */ 26 [ROC_NIX_TM_MARK_IPV4_DSCP] = 0x1, /* Byte 1 Bit[6:3] */ 27 [ROC_NIX_TM_MARK_IPV4_ECN] = 0x6, /* Byte 1 Bit[1:0], Byte 2 Bit[7:6] */ 28 [ROC_NIX_TM_MARK_IPV6_DSCP] = 0x5, /* Byte 0 Bit[2:0], Byte 1 Bit[7] */ 29 [ROC_NIX_TM_MARK_IPV6_ECN] = 0x0, /* Byte 1 Bit[7:4] */ 30 }; 31 32 static const uint64_t mark_flag[ROC_NIX_TM_MARK_MAX] = { 33 [ROC_NIX_TM_MARK_VLAN_DEI] = NIX_TM_MARK_VLAN_DEI_EN, 34 [ROC_NIX_TM_MARK_IPV4_DSCP] = NIX_TM_MARK_IP_DSCP_EN, 35 [ROC_NIX_TM_MARK_IPV4_ECN] = NIX_TM_MARK_IP_ECN_EN, 36 [ROC_NIX_TM_MARK_IPV6_DSCP] = NIX_TM_MARK_IP_DSCP_EN, 37 [ROC_NIX_TM_MARK_IPV6_ECN] = NIX_TM_MARK_IP_ECN_EN, 38 }; 39 40 static uint8_t 41 prepare_tm_shaper_red_algo(struct nix_tm_node *tm_node, volatile uint64_t *reg, 42 volatile uint64_t *regval, 43 volatile uint64_t *regval_mask) 44 { 45 uint32_t schq = tm_node->hw_id; 46 uint8_t k = 0; 47 48 plt_tm_dbg("Shaper read alg node %s(%u) lvl %u id %u, red_alg %x (%p)", 49 nix_tm_hwlvl2str(tm_node->hw_lvl), schq, tm_node->lvl, 50 tm_node->id, tm_node->red_algo, tm_node); 51 52 /* Configure just RED algo */ 53 regval[k] = ((uint64_t)tm_node->red_algo << 9); 54 regval_mask[k] = ~(BIT_ULL(10) | BIT_ULL(9)); 55 56 switch (tm_node->hw_lvl) { 57 case NIX_TXSCH_LVL_SMQ: 58 reg[k] = NIX_AF_MDQX_SHAPE(schq); 59 k++; 60 break; 61 case NIX_TXSCH_LVL_TL4: 62 reg[k] = NIX_AF_TL4X_SHAPE(schq); 63 k++; 64 break; 65 case NIX_TXSCH_LVL_TL3: 66 reg[k] = NIX_AF_TL3X_SHAPE(schq); 67 k++; 68 break; 69 case NIX_TXSCH_LVL_TL2: 70 reg[k] = NIX_AF_TL2X_SHAPE(schq); 71 k++; 72 break; 73 default: 74 break; 75 } 76 77 return k; 78 } 79 80 /* Only called while device is stopped */ 81 static int 82 nix_tm_update_red_algo(struct nix *nix, bool red_send) 83 { 84 struct mbox *mbox = (&nix->dev)->mbox; 85 struct nix_txschq_config *req; 86 struct nix_tm_node_list *list; 87 struct nix_tm_node *tm_node; 88 uint8_t k; 89 int rc; 90 91 list = nix_tm_node_list(nix, nix->tm_tree); 92 TAILQ_FOREACH(tm_node, list, node) { 93 /* Skip leaf nodes */ 94 if (nix_tm_is_leaf(nix, tm_node->lvl)) 95 continue; 96 97 if (tm_node->hw_lvl == NIX_TXSCH_LVL_TL1) 98 continue; 99 100 /* Skip if no update of red_algo is needed */ 101 if ((red_send && (tm_node->red_algo == NIX_REDALG_SEND)) || 102 (!red_send && (tm_node->red_algo != NIX_REDALG_SEND))) 103 continue; 104 105 /* Update Red algo */ 106 if (red_send) 107 tm_node->red_algo = NIX_REDALG_SEND; 108 else 109 tm_node->red_algo = NIX_REDALG_STD; 110 111 /* Update txschq config */ 112 req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox)); 113 if (req == NULL) { 114 mbox_put(mbox); 115 return -ENOSPC; 116 } 117 118 req->lvl = tm_node->hw_lvl; 119 k = prepare_tm_shaper_red_algo(tm_node, req->reg, req->regval, 120 req->regval_mask); 121 req->num_regs = k; 122 123 rc = mbox_process(mbox); 124 if (rc) { 125 mbox_put(mbox); 126 return rc; 127 } 128 mbox_put(mbox); 129 } 130 return 0; 131 } 132 133 /* Return's true if queue reconfig is needed */ 134 static bool 135 nix_tm_update_markfmt(struct nix *nix, enum roc_nix_tm_mark type, 136 int mark_yellow, int mark_red) 137 { 138 uint64_t new_markfmt, old_markfmt; 139 uint8_t *tm_markfmt; 140 uint8_t en_shift; 141 uint64_t mask; 142 143 if (type >= ROC_NIX_TM_MARK_MAX) 144 return false; 145 146 /* Pre-allocated mark formats for type:color combinations */ 147 tm_markfmt = nix->tm_markfmt[type]; 148 149 if (!mark_yellow && !mark_red) { 150 /* Null format to disable */ 151 new_markfmt = nix->tm_markfmt_null; 152 } else { 153 /* Marking enabled with combination of yellow and red */ 154 if (mark_yellow && mark_red) 155 new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y_R]; 156 else if (mark_yellow) 157 new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y]; 158 else 159 new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_R]; 160 } 161 162 mask = 0xFFull; 163 /* Format of fast path markfmt 164 * ipv6_ecn[8]:ipv4_ecn[8]:ipv6_dscp[8]:ipv4_dscp[8]:vlan_dei[16] 165 * fmt[7] = ptr offset for IPv4/IPv6 on l2_len. 166 * fmt[6:0] = markfmt idx. 167 */ 168 switch (type) { 169 case ROC_NIX_TM_MARK_VLAN_DEI: 170 en_shift = NIX_TM_MARK_VLAN_DEI_SHIFT; 171 mask = 0xFFFFull; 172 new_markfmt |= new_markfmt << 8; 173 break; 174 case ROC_NIX_TM_MARK_IPV4_DSCP: 175 new_markfmt |= BIT_ULL(7); 176 en_shift = NIX_TM_MARK_IPV4_DSCP_SHIFT; 177 break; 178 case ROC_NIX_TM_MARK_IPV4_ECN: 179 new_markfmt |= BIT_ULL(7); 180 en_shift = NIX_TM_MARK_IPV4_ECN_SHIFT; 181 break; 182 case ROC_NIX_TM_MARK_IPV6_DSCP: 183 en_shift = NIX_TM_MARK_IPV6_DSCP_SHIFT; 184 break; 185 case ROC_NIX_TM_MARK_IPV6_ECN: 186 new_markfmt |= BIT_ULL(7); 187 en_shift = NIX_TM_MARK_IPV6_ECN_SHIFT; 188 break; 189 default: 190 return false; 191 } 192 193 /* Skip if same as old config */ 194 old_markfmt = (nix->tm_markfmt_en >> en_shift) & mask; 195 if (old_markfmt == new_markfmt) 196 return false; 197 198 /* Need queue reconfig */ 199 nix->tm_markfmt_en &= ~(mask << en_shift); 200 nix->tm_markfmt_en |= (new_markfmt << en_shift); 201 202 return true; 203 } 204 205 int 206 nix_tm_mark_init(struct nix *nix) 207 { 208 struct mbox *mbox = mbox_get((&nix->dev)->mbox); 209 struct nix_mark_format_cfg_rsp *rsp; 210 struct nix_mark_format_cfg *req; 211 int rc, i, j; 212 213 /* Check for supported revisions */ 214 if (roc_model_is_cn96_ax() || roc_model_is_cn95_a0()) { 215 rc = 0; 216 goto exit; 217 } 218 219 /* Null mark format */ 220 req = mbox_alloc_msg_nix_mark_format_cfg(mbox); 221 if (req == NULL) { 222 rc = -ENOSPC; 223 goto exit; 224 } 225 226 rc = mbox_process_msg(mbox, (void *)&rsp); 227 if (rc) { 228 plt_err("TM failed to alloc null mark format, rc=%d", rc); 229 goto exit; 230 } 231 232 nix->tm_markfmt_null = rsp->mark_format_idx; 233 234 /* Alloc vlan, dscp, ecn mark formats */ 235 for (i = 0; i < ROC_NIX_TM_MARK_MAX; i++) { 236 for (j = 0; j < ROC_NIX_TM_MARK_COLOR_MAX; j++) { 237 req = mbox_alloc_msg_nix_mark_format_cfg(mbox); 238 if (req == NULL) 239 return -ENOSPC; 240 241 req->offset = mark_off[i]; 242 243 switch (j) { 244 case ROC_NIX_TM_MARK_COLOR_Y: 245 req->y_mask = y_mask_val[i][0]; 246 req->y_val = y_mask_val[i][1]; 247 break; 248 case ROC_NIX_TM_MARK_COLOR_R: 249 req->r_mask = r_mask_val[i][0]; 250 req->r_val = r_mask_val[i][1]; 251 break; 252 case ROC_NIX_TM_MARK_COLOR_Y_R: 253 req->y_mask = y_mask_val[i][0]; 254 req->y_val = y_mask_val[i][1]; 255 req->r_mask = r_mask_val[i][0]; 256 req->r_val = r_mask_val[i][1]; 257 break; 258 } 259 260 rc = mbox_process_msg(mbox, (void *)&rsp); 261 if (rc) { 262 plt_err("TM failed to alloc mark fmt " 263 "type %u color %u, rc=%d", 264 i, j, rc); 265 goto exit; 266 } 267 268 nix->tm_markfmt[i][j] = rsp->mark_format_idx; 269 plt_tm_dbg("Mark type: %u, Mark Color:%u, id:%u", i, 270 j, nix->tm_markfmt[i][j]); 271 } 272 } 273 /* Update null mark format as default */ 274 nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_VLAN_DEI, 0, 0); 275 nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_DSCP, 0, 0); 276 nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_ECN, 0, 0); 277 nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_DSCP, 0, 0); 278 nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_ECN, 0, 0); 279 exit: 280 mbox_put(mbox); 281 return rc; 282 } 283 284 int 285 roc_nix_tm_mark_config(struct roc_nix *roc_nix, enum roc_nix_tm_mark type, 286 int mark_yellow, int mark_red) 287 { 288 struct nix *nix = roc_nix_to_nix_priv(roc_nix); 289 int rc; 290 291 if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA)) 292 return -EINVAL; 293 294 rc = nix_tm_update_markfmt(nix, type, mark_yellow, mark_red); 295 if (!rc) 296 return 0; 297 298 if (!mark_yellow && !mark_red) 299 nix->tm_flags &= ~mark_flag[type]; 300 else 301 nix->tm_flags |= mark_flag[type]; 302 303 /* Update red algo for change in mark_red */ 304 return nix_tm_update_red_algo(nix, !!mark_red); 305 } 306 307 uint64_t 308 roc_nix_tm_mark_format_get(struct roc_nix *roc_nix, uint64_t *flags) 309 { 310 struct nix *nix = roc_nix_to_nix_priv(roc_nix); 311 312 *flags = ((nix->tm_flags & NIX_TM_MARK_EN_MASK) >> 3); 313 return nix->tm_markfmt_en; 314 } 315