10b7e667eSSatha Rao /* SPDX-License-Identifier: BSD-3-Clause 20b7e667eSSatha Rao * Copyright(C) 2022 Marvell. 30b7e667eSSatha Rao */ 40b7e667eSSatha Rao 50b7e667eSSatha Rao #include "roc_api.h" 60b7e667eSSatha Rao #include "roc_priv.h" 70b7e667eSSatha Rao 80b7e667eSSatha Rao static const uint8_t y_mask_val[ROC_NIX_TM_MARK_MAX][2] = { 90b7e667eSSatha Rao [ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8}, 100b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_DSCP] = {0x1, 0x2}, 110b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc}, 120b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_DSCP] = {0x1, 0x2}, 130b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3}, 140b7e667eSSatha Rao }; 150b7e667eSSatha Rao 160b7e667eSSatha Rao static const uint8_t r_mask_val[ROC_NIX_TM_MARK_MAX][2] = { 170b7e667eSSatha Rao [ROC_NIX_TM_MARK_VLAN_DEI] = {0x0, 0x8}, 180b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_DSCP] = {0x0, 0x3}, 190b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_ECN] = {0x0, 0xc}, 200b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_DSCP] = {0x0, 0x3}, 210b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_ECN] = {0x0, 0x3}, 220b7e667eSSatha Rao }; 230b7e667eSSatha Rao 240b7e667eSSatha Rao static const uint8_t mark_off[ROC_NIX_TM_MARK_MAX] = { 250b7e667eSSatha Rao [ROC_NIX_TM_MARK_VLAN_DEI] = 0x3, /* Byte 14 Bit[4:1] */ 260b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_DSCP] = 0x1, /* Byte 1 Bit[6:3] */ 270b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_ECN] = 0x6, /* Byte 1 Bit[1:0], Byte 2 Bit[7:6] */ 280b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_DSCP] = 0x5, /* Byte 0 Bit[2:0], Byte 1 Bit[7] */ 290b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_ECN] = 0x0, /* Byte 1 Bit[7:4] */ 300b7e667eSSatha Rao }; 310b7e667eSSatha Rao 320b7e667eSSatha Rao static const uint64_t mark_flag[ROC_NIX_TM_MARK_MAX] = { 330b7e667eSSatha Rao [ROC_NIX_TM_MARK_VLAN_DEI] = NIX_TM_MARK_VLAN_DEI_EN, 340b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_DSCP] = NIX_TM_MARK_IP_DSCP_EN, 350b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV4_ECN] = NIX_TM_MARK_IP_ECN_EN, 360b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_DSCP] = NIX_TM_MARK_IP_DSCP_EN, 370b7e667eSSatha Rao [ROC_NIX_TM_MARK_IPV6_ECN] = NIX_TM_MARK_IP_ECN_EN, 380b7e667eSSatha Rao }; 390b7e667eSSatha Rao 400b7e667eSSatha Rao static uint8_t 410b7e667eSSatha Rao prepare_tm_shaper_red_algo(struct nix_tm_node *tm_node, volatile uint64_t *reg, 420b7e667eSSatha Rao volatile uint64_t *regval, 430b7e667eSSatha Rao volatile uint64_t *regval_mask) 440b7e667eSSatha Rao { 450b7e667eSSatha Rao uint32_t schq = tm_node->hw_id; 460b7e667eSSatha Rao uint8_t k = 0; 470b7e667eSSatha Rao 480b7e667eSSatha Rao plt_tm_dbg("Shaper read alg node %s(%u) lvl %u id %u, red_alg %x (%p)", 490b7e667eSSatha Rao nix_tm_hwlvl2str(tm_node->hw_lvl), schq, tm_node->lvl, 500b7e667eSSatha Rao tm_node->id, tm_node->red_algo, tm_node); 510b7e667eSSatha Rao 520b7e667eSSatha Rao /* Configure just RED algo */ 530b7e667eSSatha Rao regval[k] = ((uint64_t)tm_node->red_algo << 9); 540b7e667eSSatha Rao regval_mask[k] = ~(BIT_ULL(10) | BIT_ULL(9)); 550b7e667eSSatha Rao 560b7e667eSSatha Rao switch (tm_node->hw_lvl) { 570b7e667eSSatha Rao case NIX_TXSCH_LVL_SMQ: 580b7e667eSSatha Rao reg[k] = NIX_AF_MDQX_SHAPE(schq); 590b7e667eSSatha Rao k++; 600b7e667eSSatha Rao break; 610b7e667eSSatha Rao case NIX_TXSCH_LVL_TL4: 620b7e667eSSatha Rao reg[k] = NIX_AF_TL4X_SHAPE(schq); 630b7e667eSSatha Rao k++; 640b7e667eSSatha Rao break; 650b7e667eSSatha Rao case NIX_TXSCH_LVL_TL3: 660b7e667eSSatha Rao reg[k] = NIX_AF_TL3X_SHAPE(schq); 670b7e667eSSatha Rao k++; 680b7e667eSSatha Rao break; 690b7e667eSSatha Rao case NIX_TXSCH_LVL_TL2: 700b7e667eSSatha Rao reg[k] = NIX_AF_TL2X_SHAPE(schq); 710b7e667eSSatha Rao k++; 720b7e667eSSatha Rao break; 730b7e667eSSatha Rao default: 740b7e667eSSatha Rao break; 750b7e667eSSatha Rao } 760b7e667eSSatha Rao 770b7e667eSSatha Rao return k; 780b7e667eSSatha Rao } 790b7e667eSSatha Rao 800b7e667eSSatha Rao /* Only called while device is stopped */ 810b7e667eSSatha Rao static int 820b7e667eSSatha Rao nix_tm_update_red_algo(struct nix *nix, bool red_send) 830b7e667eSSatha Rao { 840b7e667eSSatha Rao struct mbox *mbox = (&nix->dev)->mbox; 850b7e667eSSatha Rao struct nix_txschq_config *req; 860b7e667eSSatha Rao struct nix_tm_node_list *list; 870b7e667eSSatha Rao struct nix_tm_node *tm_node; 880b7e667eSSatha Rao uint8_t k; 890b7e667eSSatha Rao int rc; 900b7e667eSSatha Rao 910b7e667eSSatha Rao list = nix_tm_node_list(nix, nix->tm_tree); 920b7e667eSSatha Rao TAILQ_FOREACH(tm_node, list, node) { 930b7e667eSSatha Rao /* Skip leaf nodes */ 940b7e667eSSatha Rao if (nix_tm_is_leaf(nix, tm_node->lvl)) 950b7e667eSSatha Rao continue; 960b7e667eSSatha Rao 970b7e667eSSatha Rao if (tm_node->hw_lvl == NIX_TXSCH_LVL_TL1) 980b7e667eSSatha Rao continue; 990b7e667eSSatha Rao 1000b7e667eSSatha Rao /* Skip if no update of red_algo is needed */ 1010b7e667eSSatha Rao if ((red_send && (tm_node->red_algo == NIX_REDALG_SEND)) || 1020b7e667eSSatha Rao (!red_send && (tm_node->red_algo != NIX_REDALG_SEND))) 1030b7e667eSSatha Rao continue; 1040b7e667eSSatha Rao 1050b7e667eSSatha Rao /* Update Red algo */ 1060b7e667eSSatha Rao if (red_send) 1070b7e667eSSatha Rao tm_node->red_algo = NIX_REDALG_SEND; 1080b7e667eSSatha Rao else 1090b7e667eSSatha Rao tm_node->red_algo = NIX_REDALG_STD; 1100b7e667eSSatha Rao 1110b7e667eSSatha Rao /* Update txschq config */ 11244a9307cSRakesh Kudurumalla req = mbox_alloc_msg_nix_txschq_cfg(mbox_get(mbox)); 11344a9307cSRakesh Kudurumalla if (req == NULL) { 11444a9307cSRakesh Kudurumalla mbox_put(mbox); 115e746aec1SSatha Rao return -ENOSPC; 11644a9307cSRakesh Kudurumalla } 117e746aec1SSatha Rao 1180b7e667eSSatha Rao req->lvl = tm_node->hw_lvl; 1190b7e667eSSatha Rao k = prepare_tm_shaper_red_algo(tm_node, req->reg, req->regval, 1200b7e667eSSatha Rao req->regval_mask); 1210b7e667eSSatha Rao req->num_regs = k; 1220b7e667eSSatha Rao 1230b7e667eSSatha Rao rc = mbox_process(mbox); 12444a9307cSRakesh Kudurumalla if (rc) { 12544a9307cSRakesh Kudurumalla mbox_put(mbox); 1260b7e667eSSatha Rao return rc; 1270b7e667eSSatha Rao } 12844a9307cSRakesh Kudurumalla mbox_put(mbox); 12944a9307cSRakesh Kudurumalla } 1300b7e667eSSatha Rao return 0; 1310b7e667eSSatha Rao } 1320b7e667eSSatha Rao 1330b7e667eSSatha Rao /* Return's true if queue reconfig is needed */ 1340b7e667eSSatha Rao static bool 1350b7e667eSSatha Rao nix_tm_update_markfmt(struct nix *nix, enum roc_nix_tm_mark type, 1360b7e667eSSatha Rao int mark_yellow, int mark_red) 1370b7e667eSSatha Rao { 1380b7e667eSSatha Rao uint64_t new_markfmt, old_markfmt; 1390b7e667eSSatha Rao uint8_t *tm_markfmt; 1400b7e667eSSatha Rao uint8_t en_shift; 1410b7e667eSSatha Rao uint64_t mask; 1420b7e667eSSatha Rao 1430b7e667eSSatha Rao if (type >= ROC_NIX_TM_MARK_MAX) 1440b7e667eSSatha Rao return false; 1450b7e667eSSatha Rao 1460b7e667eSSatha Rao /* Pre-allocated mark formats for type:color combinations */ 1470b7e667eSSatha Rao tm_markfmt = nix->tm_markfmt[type]; 1480b7e667eSSatha Rao 1490b7e667eSSatha Rao if (!mark_yellow && !mark_red) { 1500b7e667eSSatha Rao /* Null format to disable */ 1510b7e667eSSatha Rao new_markfmt = nix->tm_markfmt_null; 1520b7e667eSSatha Rao } else { 1530b7e667eSSatha Rao /* Marking enabled with combination of yellow and red */ 1540b7e667eSSatha Rao if (mark_yellow && mark_red) 1550b7e667eSSatha Rao new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y_R]; 1560b7e667eSSatha Rao else if (mark_yellow) 1570b7e667eSSatha Rao new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_Y]; 1580b7e667eSSatha Rao else 1590b7e667eSSatha Rao new_markfmt = tm_markfmt[ROC_NIX_TM_MARK_COLOR_R]; 1600b7e667eSSatha Rao } 1610b7e667eSSatha Rao 1620b7e667eSSatha Rao mask = 0xFFull; 1630b7e667eSSatha Rao /* Format of fast path markfmt 1640b7e667eSSatha Rao * ipv6_ecn[8]:ipv4_ecn[8]:ipv6_dscp[8]:ipv4_dscp[8]:vlan_dei[16] 1650b7e667eSSatha Rao * fmt[7] = ptr offset for IPv4/IPv6 on l2_len. 1660b7e667eSSatha Rao * fmt[6:0] = markfmt idx. 1670b7e667eSSatha Rao */ 1680b7e667eSSatha Rao switch (type) { 1690b7e667eSSatha Rao case ROC_NIX_TM_MARK_VLAN_DEI: 1700b7e667eSSatha Rao en_shift = NIX_TM_MARK_VLAN_DEI_SHIFT; 1710b7e667eSSatha Rao mask = 0xFFFFull; 1720b7e667eSSatha Rao new_markfmt |= new_markfmt << 8; 1730b7e667eSSatha Rao break; 1740b7e667eSSatha Rao case ROC_NIX_TM_MARK_IPV4_DSCP: 1750b7e667eSSatha Rao new_markfmt |= BIT_ULL(7); 1760b7e667eSSatha Rao en_shift = NIX_TM_MARK_IPV4_DSCP_SHIFT; 1770b7e667eSSatha Rao break; 1780b7e667eSSatha Rao case ROC_NIX_TM_MARK_IPV4_ECN: 1790b7e667eSSatha Rao new_markfmt |= BIT_ULL(7); 1800b7e667eSSatha Rao en_shift = NIX_TM_MARK_IPV4_ECN_SHIFT; 1810b7e667eSSatha Rao break; 1820b7e667eSSatha Rao case ROC_NIX_TM_MARK_IPV6_DSCP: 1830b7e667eSSatha Rao en_shift = NIX_TM_MARK_IPV6_DSCP_SHIFT; 1840b7e667eSSatha Rao break; 1850b7e667eSSatha Rao case ROC_NIX_TM_MARK_IPV6_ECN: 1860b7e667eSSatha Rao new_markfmt |= BIT_ULL(7); 1870b7e667eSSatha Rao en_shift = NIX_TM_MARK_IPV6_ECN_SHIFT; 1880b7e667eSSatha Rao break; 1890b7e667eSSatha Rao default: 1900b7e667eSSatha Rao return false; 1910b7e667eSSatha Rao } 1920b7e667eSSatha Rao 1930b7e667eSSatha Rao /* Skip if same as old config */ 1940b7e667eSSatha Rao old_markfmt = (nix->tm_markfmt_en >> en_shift) & mask; 1950b7e667eSSatha Rao if (old_markfmt == new_markfmt) 1960b7e667eSSatha Rao return false; 1970b7e667eSSatha Rao 1980b7e667eSSatha Rao /* Need queue reconfig */ 1990b7e667eSSatha Rao nix->tm_markfmt_en &= ~(mask << en_shift); 2000b7e667eSSatha Rao nix->tm_markfmt_en |= (new_markfmt << en_shift); 2010b7e667eSSatha Rao 2020b7e667eSSatha Rao return true; 2030b7e667eSSatha Rao } 2040b7e667eSSatha Rao 2050b7e667eSSatha Rao int 2060b7e667eSSatha Rao nix_tm_mark_init(struct nix *nix) 2070b7e667eSSatha Rao { 20844a9307cSRakesh Kudurumalla struct mbox *mbox = mbox_get((&nix->dev)->mbox); 2090b7e667eSSatha Rao struct nix_mark_format_cfg_rsp *rsp; 2100b7e667eSSatha Rao struct nix_mark_format_cfg *req; 2110b7e667eSSatha Rao int rc, i, j; 2120b7e667eSSatha Rao 2130b7e667eSSatha Rao /* Check for supported revisions */ 21444a9307cSRakesh Kudurumalla if (roc_model_is_cn96_ax() || roc_model_is_cn95_a0()) { 21544a9307cSRakesh Kudurumalla rc = 0; 21644a9307cSRakesh Kudurumalla goto exit; 21744a9307cSRakesh Kudurumalla } 2180b7e667eSSatha Rao 2190b7e667eSSatha Rao /* Null mark format */ 2200b7e667eSSatha Rao req = mbox_alloc_msg_nix_mark_format_cfg(mbox); 22144a9307cSRakesh Kudurumalla if (req == NULL) { 22244a9307cSRakesh Kudurumalla rc = -ENOSPC; 22344a9307cSRakesh Kudurumalla goto exit; 22444a9307cSRakesh Kudurumalla } 225e746aec1SSatha Rao 2260b7e667eSSatha Rao rc = mbox_process_msg(mbox, (void *)&rsp); 2270b7e667eSSatha Rao if (rc) { 2280b7e667eSSatha Rao plt_err("TM failed to alloc null mark format, rc=%d", rc); 2290b7e667eSSatha Rao goto exit; 2300b7e667eSSatha Rao } 2310b7e667eSSatha Rao 2320b7e667eSSatha Rao nix->tm_markfmt_null = rsp->mark_format_idx; 2330b7e667eSSatha Rao 2340b7e667eSSatha Rao /* Alloc vlan, dscp, ecn mark formats */ 2350b7e667eSSatha Rao for (i = 0; i < ROC_NIX_TM_MARK_MAX; i++) { 2360b7e667eSSatha Rao for (j = 0; j < ROC_NIX_TM_MARK_COLOR_MAX; j++) { 2370b7e667eSSatha Rao req = mbox_alloc_msg_nix_mark_format_cfg(mbox); 238e746aec1SSatha Rao if (req == NULL) 239e746aec1SSatha Rao return -ENOSPC; 240e746aec1SSatha Rao 2410b7e667eSSatha Rao req->offset = mark_off[i]; 2420b7e667eSSatha Rao 2430b7e667eSSatha Rao switch (j) { 2440b7e667eSSatha Rao case ROC_NIX_TM_MARK_COLOR_Y: 2450b7e667eSSatha Rao req->y_mask = y_mask_val[i][0]; 2460b7e667eSSatha Rao req->y_val = y_mask_val[i][1]; 2470b7e667eSSatha Rao break; 2480b7e667eSSatha Rao case ROC_NIX_TM_MARK_COLOR_R: 2490b7e667eSSatha Rao req->r_mask = r_mask_val[i][0]; 2500b7e667eSSatha Rao req->r_val = r_mask_val[i][1]; 2510b7e667eSSatha Rao break; 2520b7e667eSSatha Rao case ROC_NIX_TM_MARK_COLOR_Y_R: 2530b7e667eSSatha Rao req->y_mask = y_mask_val[i][0]; 2540b7e667eSSatha Rao req->y_val = y_mask_val[i][1]; 2550b7e667eSSatha Rao req->r_mask = r_mask_val[i][0]; 2560b7e667eSSatha Rao req->r_val = r_mask_val[i][1]; 2570b7e667eSSatha Rao break; 2580b7e667eSSatha Rao } 2590b7e667eSSatha Rao 2600b7e667eSSatha Rao rc = mbox_process_msg(mbox, (void *)&rsp); 2610b7e667eSSatha Rao if (rc) { 2620b7e667eSSatha Rao plt_err("TM failed to alloc mark fmt " 2630b7e667eSSatha Rao "type %u color %u, rc=%d", 2640b7e667eSSatha Rao i, j, rc); 2650b7e667eSSatha Rao goto exit; 2660b7e667eSSatha Rao } 2670b7e667eSSatha Rao 2680b7e667eSSatha Rao nix->tm_markfmt[i][j] = rsp->mark_format_idx; 269*f665790aSDavid Marchand plt_tm_dbg("Mark type: %u, Mark Color:%u, id:%u", i, 2700b7e667eSSatha Rao j, nix->tm_markfmt[i][j]); 2710b7e667eSSatha Rao } 2720b7e667eSSatha Rao } 2730b7e667eSSatha Rao /* Update null mark format as default */ 2740b7e667eSSatha Rao nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_VLAN_DEI, 0, 0); 2750b7e667eSSatha Rao nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_DSCP, 0, 0); 2760b7e667eSSatha Rao nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV4_ECN, 0, 0); 2770b7e667eSSatha Rao nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_DSCP, 0, 0); 2780b7e667eSSatha Rao nix_tm_update_markfmt(nix, ROC_NIX_TM_MARK_IPV6_ECN, 0, 0); 2790b7e667eSSatha Rao exit: 28044a9307cSRakesh Kudurumalla mbox_put(mbox); 2810b7e667eSSatha Rao return rc; 2820b7e667eSSatha Rao } 2830b7e667eSSatha Rao 2840b7e667eSSatha Rao int 2850b7e667eSSatha Rao roc_nix_tm_mark_config(struct roc_nix *roc_nix, enum roc_nix_tm_mark type, 2860b7e667eSSatha Rao int mark_yellow, int mark_red) 2870b7e667eSSatha Rao { 2880b7e667eSSatha Rao struct nix *nix = roc_nix_to_nix_priv(roc_nix); 2890b7e667eSSatha Rao int rc; 2900b7e667eSSatha Rao 2910b7e667eSSatha Rao if (!(nix->tm_flags & NIX_TM_HIERARCHY_ENA)) 2920b7e667eSSatha Rao return -EINVAL; 2930b7e667eSSatha Rao 2940b7e667eSSatha Rao rc = nix_tm_update_markfmt(nix, type, mark_yellow, mark_red); 2950b7e667eSSatha Rao if (!rc) 2960b7e667eSSatha Rao return 0; 2970b7e667eSSatha Rao 2980b7e667eSSatha Rao if (!mark_yellow && !mark_red) 2990b7e667eSSatha Rao nix->tm_flags &= ~mark_flag[type]; 3000b7e667eSSatha Rao else 3010b7e667eSSatha Rao nix->tm_flags |= mark_flag[type]; 3020b7e667eSSatha Rao 3030b7e667eSSatha Rao /* Update red algo for change in mark_red */ 3040b7e667eSSatha Rao return nix_tm_update_red_algo(nix, !!mark_red); 3050b7e667eSSatha Rao } 3060b7e667eSSatha Rao 3070b7e667eSSatha Rao uint64_t 3080b7e667eSSatha Rao roc_nix_tm_mark_format_get(struct roc_nix *roc_nix, uint64_t *flags) 3090b7e667eSSatha Rao { 3100b7e667eSSatha Rao struct nix *nix = roc_nix_to_nix_priv(roc_nix); 3110b7e667eSSatha Rao 3120b7e667eSSatha Rao *flags = ((nix->tm_flags & NIX_TM_MARK_EN_MASK) >> 3); 3130b7e667eSSatha Rao return nix->tm_markfmt_en; 3140b7e667eSSatha Rao } 315