1d2185e79SDaniel Machon // SPDX-License-Identifier: GPL-2.0+ 2d2185e79SDaniel Machon /* Microchip Sparx5 Switch driver 3d2185e79SDaniel Machon * 4d2185e79SDaniel Machon * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries. 5d2185e79SDaniel Machon */ 6d2185e79SDaniel Machon 7d2185e79SDaniel Machon #include "sparx5_main_regs.h" 8d2185e79SDaniel Machon #include "sparx5_main.h" 9d2185e79SDaniel Machon 10*ae3e691fSDaniel Machon #define SPX5_PSFP_SF_CNT 1024 11c70a5e2cSDaniel Machon #define SPX5_PSFP_SG_CONFIG_CHANGE_SLEEP 1000 12c70a5e2cSDaniel Machon #define SPX5_PSFP_SG_CONFIG_CHANGE_TIMEO 100000 13c70a5e2cSDaniel Machon 14d2185e79SDaniel Machon /* Pool of available service policers */ 15d2185e79SDaniel Machon static struct sparx5_pool_entry sparx5_psfp_fm_pool[SPX5_SDLB_CNT]; 16d2185e79SDaniel Machon 17c70a5e2cSDaniel Machon /* Pool of available stream gates */ 18c70a5e2cSDaniel Machon static struct sparx5_pool_entry sparx5_psfp_sg_pool[SPX5_PSFP_SG_CNT]; 19c70a5e2cSDaniel Machon 20*ae3e691fSDaniel Machon /* Pool of available stream filters */ 21*ae3e691fSDaniel Machon static struct sparx5_pool_entry sparx5_psfp_sf_pool[SPX5_PSFP_SF_CNT]; 22*ae3e691fSDaniel Machon 23*ae3e691fSDaniel Machon static int sparx5_psfp_sf_get(u32 *id) 24*ae3e691fSDaniel Machon { 25*ae3e691fSDaniel Machon return sparx5_pool_get(sparx5_psfp_sf_pool, SPX5_PSFP_SF_CNT, id); 26*ae3e691fSDaniel Machon } 27*ae3e691fSDaniel Machon 28*ae3e691fSDaniel Machon static int sparx5_psfp_sf_put(u32 id) 29*ae3e691fSDaniel Machon { 30*ae3e691fSDaniel Machon return sparx5_pool_put(sparx5_psfp_sf_pool, SPX5_PSFP_SF_CNT, id); 31*ae3e691fSDaniel Machon } 32*ae3e691fSDaniel Machon 33c70a5e2cSDaniel Machon static int sparx5_psfp_sg_get(u32 idx, u32 *id) 34c70a5e2cSDaniel Machon { 35c70a5e2cSDaniel Machon return sparx5_pool_get_with_idx(sparx5_psfp_sg_pool, SPX5_PSFP_SG_CNT, 36c70a5e2cSDaniel Machon idx, id); 37c70a5e2cSDaniel Machon } 38c70a5e2cSDaniel Machon 39c70a5e2cSDaniel Machon static int sparx5_psfp_sg_put(u32 id) 40c70a5e2cSDaniel Machon { 41c70a5e2cSDaniel Machon return sparx5_pool_put(sparx5_psfp_sg_pool, SPX5_PSFP_SG_CNT, id); 42c70a5e2cSDaniel Machon } 43c70a5e2cSDaniel Machon 44d2185e79SDaniel Machon static int sparx5_psfp_fm_get(u32 idx, u32 *id) 45d2185e79SDaniel Machon { 46d2185e79SDaniel Machon return sparx5_pool_get_with_idx(sparx5_psfp_fm_pool, SPX5_SDLB_CNT, idx, 47d2185e79SDaniel Machon id); 48d2185e79SDaniel Machon } 49d2185e79SDaniel Machon 50d2185e79SDaniel Machon static int sparx5_psfp_fm_put(u32 id) 51d2185e79SDaniel Machon { 52d2185e79SDaniel Machon return sparx5_pool_put(sparx5_psfp_fm_pool, SPX5_SDLB_CNT, id); 53d2185e79SDaniel Machon } 54d2185e79SDaniel Machon 55*ae3e691fSDaniel Machon u32 sparx5_psfp_isdx_get_sf(struct sparx5 *sparx5, u32 isdx) 56*ae3e691fSDaniel Machon { 57*ae3e691fSDaniel Machon return ANA_L2_TSN_CFG_TSN_SFID_GET(spx5_rd(sparx5, 58*ae3e691fSDaniel Machon ANA_L2_TSN_CFG(isdx))); 59*ae3e691fSDaniel Machon } 60*ae3e691fSDaniel Machon 61*ae3e691fSDaniel Machon u32 sparx5_psfp_isdx_get_fm(struct sparx5 *sparx5, u32 isdx) 62*ae3e691fSDaniel Machon { 63*ae3e691fSDaniel Machon return ANA_L2_DLB_CFG_DLB_IDX_GET(spx5_rd(sparx5, 64*ae3e691fSDaniel Machon ANA_L2_DLB_CFG(isdx))); 65*ae3e691fSDaniel Machon } 66*ae3e691fSDaniel Machon 67*ae3e691fSDaniel Machon u32 sparx5_psfp_sf_get_sg(struct sparx5 *sparx5, u32 sfid) 68*ae3e691fSDaniel Machon { 69*ae3e691fSDaniel Machon return ANA_AC_TSN_SF_CFG_TSN_SGID_GET(spx5_rd(sparx5, 70*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG(sfid))); 71*ae3e691fSDaniel Machon } 72*ae3e691fSDaniel Machon 73*ae3e691fSDaniel Machon void sparx5_isdx_conf_set(struct sparx5 *sparx5, u32 isdx, u32 sfid, u32 fmid) 74*ae3e691fSDaniel Machon { 75*ae3e691fSDaniel Machon spx5_rmw(ANA_L2_TSN_CFG_TSN_SFID_SET(sfid), ANA_L2_TSN_CFG_TSN_SFID, 76*ae3e691fSDaniel Machon sparx5, ANA_L2_TSN_CFG(isdx)); 77*ae3e691fSDaniel Machon 78*ae3e691fSDaniel Machon spx5_rmw(ANA_L2_DLB_CFG_DLB_IDX_SET(fmid), ANA_L2_DLB_CFG_DLB_IDX, 79*ae3e691fSDaniel Machon sparx5, ANA_L2_DLB_CFG(isdx)); 80*ae3e691fSDaniel Machon } 81*ae3e691fSDaniel Machon 82c70a5e2cSDaniel Machon /* Internal priority value to internal priority selector */ 83c70a5e2cSDaniel Machon static u32 sparx5_psfp_ipv_to_ips(s32 ipv) 84c70a5e2cSDaniel Machon { 85c70a5e2cSDaniel Machon return ipv > 0 ? (ipv | BIT(3)) : 0; 86c70a5e2cSDaniel Machon } 87c70a5e2cSDaniel Machon 88c70a5e2cSDaniel Machon static int sparx5_psfp_sgid_get_status(struct sparx5 *sparx5) 89c70a5e2cSDaniel Machon { 90c70a5e2cSDaniel Machon return spx5_rd(sparx5, ANA_AC_SG_ACCESS_CTRL); 91c70a5e2cSDaniel Machon } 92c70a5e2cSDaniel Machon 93c70a5e2cSDaniel Machon static int sparx5_psfp_sgid_wait_for_completion(struct sparx5 *sparx5) 94c70a5e2cSDaniel Machon { 95c70a5e2cSDaniel Machon u32 val; 96c70a5e2cSDaniel Machon 97c70a5e2cSDaniel Machon return readx_poll_timeout(sparx5_psfp_sgid_get_status, sparx5, val, 98c70a5e2cSDaniel Machon !ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_GET(val), 99c70a5e2cSDaniel Machon SPX5_PSFP_SG_CONFIG_CHANGE_SLEEP, 100c70a5e2cSDaniel Machon SPX5_PSFP_SG_CONFIG_CHANGE_TIMEO); 101c70a5e2cSDaniel Machon } 102c70a5e2cSDaniel Machon 103c70a5e2cSDaniel Machon static void sparx5_psfp_sg_config_change(struct sparx5 *sparx5, u32 id) 104c70a5e2cSDaniel Machon { 105c70a5e2cSDaniel Machon spx5_wr(ANA_AC_SG_ACCESS_CTRL_SGID_SET(id), sparx5, 106c70a5e2cSDaniel Machon ANA_AC_SG_ACCESS_CTRL); 107c70a5e2cSDaniel Machon 108c70a5e2cSDaniel Machon spx5_wr(ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_SET(1) | 109c70a5e2cSDaniel Machon ANA_AC_SG_ACCESS_CTRL_SGID_SET(id), 110c70a5e2cSDaniel Machon sparx5, ANA_AC_SG_ACCESS_CTRL); 111c70a5e2cSDaniel Machon 112c70a5e2cSDaniel Machon if (sparx5_psfp_sgid_wait_for_completion(sparx5) < 0) 113c70a5e2cSDaniel Machon pr_debug("%s:%d timed out waiting for sgid completion", 114c70a5e2cSDaniel Machon __func__, __LINE__); 115c70a5e2cSDaniel Machon } 116c70a5e2cSDaniel Machon 117*ae3e691fSDaniel Machon static void sparx5_psfp_sf_set(struct sparx5 *sparx5, u32 id, 118*ae3e691fSDaniel Machon const struct sparx5_psfp_sf *sf) 119*ae3e691fSDaniel Machon { 120*ae3e691fSDaniel Machon /* Configure stream gate*/ 121*ae3e691fSDaniel Machon spx5_rmw(ANA_AC_TSN_SF_CFG_TSN_SGID_SET(sf->sgid) | 122*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_TSN_MAX_SDU_SET(sf->max_sdu) | 123*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE_SET(sf->sblock_osize) | 124*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_ENA_SET(sf->sblock_osize_ena), 125*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_TSN_SGID | ANA_AC_TSN_SF_CFG_TSN_MAX_SDU | 126*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE | 127*ae3e691fSDaniel Machon ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_ENA, 128*ae3e691fSDaniel Machon sparx5, ANA_AC_TSN_SF_CFG(id)); 129*ae3e691fSDaniel Machon } 130*ae3e691fSDaniel Machon 131c70a5e2cSDaniel Machon static int sparx5_psfp_sg_set(struct sparx5 *sparx5, u32 id, 132c70a5e2cSDaniel Machon const struct sparx5_psfp_sg *sg) 133c70a5e2cSDaniel Machon { 134c70a5e2cSDaniel Machon u32 ips, base_lsb, base_msb, accum_time_interval = 0; 135c70a5e2cSDaniel Machon const struct sparx5_psfp_gce *gce; 136c70a5e2cSDaniel Machon int i; 137c70a5e2cSDaniel Machon 138c70a5e2cSDaniel Machon ips = sparx5_psfp_ipv_to_ips(sg->ipv); 139c70a5e2cSDaniel Machon base_lsb = sg->basetime.tv_sec & 0xffffffff; 140c70a5e2cSDaniel Machon base_msb = sg->basetime.tv_sec >> 32; 141c70a5e2cSDaniel Machon 142c70a5e2cSDaniel Machon /* Set stream gate id */ 143c70a5e2cSDaniel Machon spx5_wr(ANA_AC_SG_ACCESS_CTRL_SGID_SET(id), sparx5, 144c70a5e2cSDaniel Machon ANA_AC_SG_ACCESS_CTRL); 145c70a5e2cSDaniel Machon 146c70a5e2cSDaniel Machon /* Write AdminPSFP values */ 147c70a5e2cSDaniel Machon spx5_wr(sg->basetime.tv_nsec, sparx5, ANA_AC_SG_CONFIG_REG_1); 148c70a5e2cSDaniel Machon spx5_wr(base_lsb, sparx5, ANA_AC_SG_CONFIG_REG_2); 149c70a5e2cSDaniel Machon 150c70a5e2cSDaniel Machon spx5_rmw(ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_SET(base_msb) | 151c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_INIT_IPS_SET(ips) | 152c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_LIST_LENGTH_SET(sg->num_entries) | 153c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_INIT_GATE_STATE_SET(sg->gate_state) | 154c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_GATE_ENABLE_SET(1), 155c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB | 156c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_INIT_IPS | 157c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_LIST_LENGTH | 158c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_INIT_GATE_STATE | 159c70a5e2cSDaniel Machon ANA_AC_SG_CONFIG_REG_3_GATE_ENABLE, 160c70a5e2cSDaniel Machon sparx5, ANA_AC_SG_CONFIG_REG_3); 161c70a5e2cSDaniel Machon 162c70a5e2cSDaniel Machon spx5_wr(sg->cycletime, sparx5, ANA_AC_SG_CONFIG_REG_4); 163c70a5e2cSDaniel Machon spx5_wr(sg->cycletimeext, sparx5, ANA_AC_SG_CONFIG_REG_5); 164c70a5e2cSDaniel Machon 165c70a5e2cSDaniel Machon /* For each scheduling entry */ 166c70a5e2cSDaniel Machon for (i = 0; i < sg->num_entries; i++) { 167c70a5e2cSDaniel Machon gce = &sg->gce[i]; 168c70a5e2cSDaniel Machon ips = sparx5_psfp_ipv_to_ips(gce->ipv); 169c70a5e2cSDaniel Machon /* hardware needs TimeInterval to be cumulative */ 170c70a5e2cSDaniel Machon accum_time_interval += gce->interval; 171c70a5e2cSDaniel Machon /* Set gate state */ 172c70a5e2cSDaniel Machon spx5_wr(ANA_AC_SG_GCL_GS_CONFIG_IPS_SET(ips) | 173c70a5e2cSDaniel Machon ANA_AC_SG_GCL_GS_CONFIG_GATE_STATE_SET(gce->gate_state), 174c70a5e2cSDaniel Machon sparx5, ANA_AC_SG_GCL_GS_CONFIG(i)); 175c70a5e2cSDaniel Machon 176c70a5e2cSDaniel Machon /* Set time interval */ 177c70a5e2cSDaniel Machon spx5_wr(accum_time_interval, sparx5, 178c70a5e2cSDaniel Machon ANA_AC_SG_GCL_TI_CONFIG(i)); 179c70a5e2cSDaniel Machon 180c70a5e2cSDaniel Machon /* Set maximum octets */ 181c70a5e2cSDaniel Machon spx5_wr(gce->maxoctets, sparx5, ANA_AC_SG_GCL_OCT_CONFIG(i)); 182c70a5e2cSDaniel Machon } 183c70a5e2cSDaniel Machon 184c70a5e2cSDaniel Machon return 0; 185c70a5e2cSDaniel Machon } 186c70a5e2cSDaniel Machon 187d2185e79SDaniel Machon static int sparx5_sdlb_conf_set(struct sparx5 *sparx5, 188d2185e79SDaniel Machon struct sparx5_psfp_fm *fm) 189d2185e79SDaniel Machon { 190d2185e79SDaniel Machon int (*sparx5_sdlb_group_action)(struct sparx5 *sparx5, u32 group, 191d2185e79SDaniel Machon u32 idx); 192d2185e79SDaniel Machon 193d2185e79SDaniel Machon if (!fm->pol.rate && !fm->pol.burst) 194d2185e79SDaniel Machon sparx5_sdlb_group_action = &sparx5_sdlb_group_del; 195d2185e79SDaniel Machon else 196d2185e79SDaniel Machon sparx5_sdlb_group_action = &sparx5_sdlb_group_add; 197d2185e79SDaniel Machon 198d2185e79SDaniel Machon sparx5_policer_conf_set(sparx5, &fm->pol); 199d2185e79SDaniel Machon 200d2185e79SDaniel Machon return sparx5_sdlb_group_action(sparx5, fm->pol.group, fm->pol.idx); 201d2185e79SDaniel Machon } 202d2185e79SDaniel Machon 203*ae3e691fSDaniel Machon int sparx5_psfp_sf_add(struct sparx5 *sparx5, const struct sparx5_psfp_sf *sf, 204*ae3e691fSDaniel Machon u32 *id) 205*ae3e691fSDaniel Machon { 206*ae3e691fSDaniel Machon int ret; 207*ae3e691fSDaniel Machon 208*ae3e691fSDaniel Machon ret = sparx5_psfp_sf_get(id); 209*ae3e691fSDaniel Machon if (ret < 0) 210*ae3e691fSDaniel Machon return ret; 211*ae3e691fSDaniel Machon 212*ae3e691fSDaniel Machon sparx5_psfp_sf_set(sparx5, *id, sf); 213*ae3e691fSDaniel Machon 214*ae3e691fSDaniel Machon return 0; 215*ae3e691fSDaniel Machon } 216*ae3e691fSDaniel Machon 217*ae3e691fSDaniel Machon int sparx5_psfp_sf_del(struct sparx5 *sparx5, u32 id) 218*ae3e691fSDaniel Machon { 219*ae3e691fSDaniel Machon const struct sparx5_psfp_sf sf = { 0 }; 220*ae3e691fSDaniel Machon 221*ae3e691fSDaniel Machon sparx5_psfp_sf_set(sparx5, id, &sf); 222*ae3e691fSDaniel Machon 223*ae3e691fSDaniel Machon return sparx5_psfp_sf_put(id); 224*ae3e691fSDaniel Machon } 225*ae3e691fSDaniel Machon 226c70a5e2cSDaniel Machon int sparx5_psfp_sg_add(struct sparx5 *sparx5, u32 uidx, 227c70a5e2cSDaniel Machon struct sparx5_psfp_sg *sg, u32 *id) 228c70a5e2cSDaniel Machon { 229c70a5e2cSDaniel Machon ktime_t basetime; 230c70a5e2cSDaniel Machon int ret; 231c70a5e2cSDaniel Machon 232c70a5e2cSDaniel Machon ret = sparx5_psfp_sg_get(uidx, id); 233c70a5e2cSDaniel Machon if (ret < 0) 234c70a5e2cSDaniel Machon return ret; 235c70a5e2cSDaniel Machon /* Was already in use, no need to reconfigure */ 236c70a5e2cSDaniel Machon if (ret > 1) 237c70a5e2cSDaniel Machon return 0; 238c70a5e2cSDaniel Machon 239c70a5e2cSDaniel Machon /* Calculate basetime for this stream gate */ 240c70a5e2cSDaniel Machon sparx5_new_base_time(sparx5, sg->cycletime, 0, &basetime); 241c70a5e2cSDaniel Machon sg->basetime = ktime_to_timespec64(basetime); 242c70a5e2cSDaniel Machon 243c70a5e2cSDaniel Machon sparx5_psfp_sg_set(sparx5, *id, sg); 244c70a5e2cSDaniel Machon 245c70a5e2cSDaniel Machon /* Signal hardware to copy AdminPSFP values into OperPSFP values */ 246c70a5e2cSDaniel Machon sparx5_psfp_sg_config_change(sparx5, *id); 247c70a5e2cSDaniel Machon 248c70a5e2cSDaniel Machon return 0; 249c70a5e2cSDaniel Machon } 250c70a5e2cSDaniel Machon 251c70a5e2cSDaniel Machon int sparx5_psfp_sg_del(struct sparx5 *sparx5, u32 id) 252c70a5e2cSDaniel Machon { 253c70a5e2cSDaniel Machon const struct sparx5_psfp_sg sg = { 0 }; 254c70a5e2cSDaniel Machon int ret; 255c70a5e2cSDaniel Machon 256c70a5e2cSDaniel Machon ret = sparx5_psfp_sg_put(id); 257c70a5e2cSDaniel Machon if (ret < 0) 258c70a5e2cSDaniel Machon return ret; 259c70a5e2cSDaniel Machon /* Stream gate still in use ? */ 260c70a5e2cSDaniel Machon if (ret > 0) 261c70a5e2cSDaniel Machon return 0; 262c70a5e2cSDaniel Machon 263c70a5e2cSDaniel Machon return sparx5_psfp_sg_set(sparx5, id, &sg); 264c70a5e2cSDaniel Machon } 265c70a5e2cSDaniel Machon 266d2185e79SDaniel Machon int sparx5_psfp_fm_add(struct sparx5 *sparx5, u32 uidx, 267d2185e79SDaniel Machon struct sparx5_psfp_fm *fm, u32 *id) 268d2185e79SDaniel Machon { 269d2185e79SDaniel Machon struct sparx5_policer *pol = &fm->pol; 270d2185e79SDaniel Machon int ret; 271d2185e79SDaniel Machon 272d2185e79SDaniel Machon /* Get flow meter */ 273d2185e79SDaniel Machon ret = sparx5_psfp_fm_get(uidx, &fm->pol.idx); 274d2185e79SDaniel Machon if (ret < 0) 275d2185e79SDaniel Machon return ret; 276d2185e79SDaniel Machon /* Was already in use, no need to reconfigure */ 277d2185e79SDaniel Machon if (ret > 1) 278d2185e79SDaniel Machon return 0; 279d2185e79SDaniel Machon 280d2185e79SDaniel Machon ret = sparx5_sdlb_group_get_by_rate(sparx5, pol->rate, pol->burst); 281d2185e79SDaniel Machon if (ret < 0) 282d2185e79SDaniel Machon return ret; 283d2185e79SDaniel Machon 284d2185e79SDaniel Machon fm->pol.group = ret; 285d2185e79SDaniel Machon 286d2185e79SDaniel Machon ret = sparx5_sdlb_conf_set(sparx5, fm); 287d2185e79SDaniel Machon if (ret < 0) 288d2185e79SDaniel Machon return ret; 289d2185e79SDaniel Machon 290d2185e79SDaniel Machon *id = fm->pol.idx; 291d2185e79SDaniel Machon 292d2185e79SDaniel Machon return 0; 293d2185e79SDaniel Machon } 294d2185e79SDaniel Machon 295d2185e79SDaniel Machon int sparx5_psfp_fm_del(struct sparx5 *sparx5, u32 id) 296d2185e79SDaniel Machon { 297d2185e79SDaniel Machon struct sparx5_psfp_fm fm = { .pol.idx = id, 298d2185e79SDaniel Machon .pol.type = SPX5_POL_SERVICE }; 299d2185e79SDaniel Machon int ret; 300d2185e79SDaniel Machon 301d2185e79SDaniel Machon /* Find the group that this lb belongs to */ 302d2185e79SDaniel Machon ret = sparx5_sdlb_group_get_by_index(sparx5, id, &fm.pol.group); 303d2185e79SDaniel Machon if (ret < 0) 304d2185e79SDaniel Machon return ret; 305d2185e79SDaniel Machon 306d2185e79SDaniel Machon ret = sparx5_psfp_fm_put(id); 307d2185e79SDaniel Machon if (ret < 0) 308d2185e79SDaniel Machon return ret; 309d2185e79SDaniel Machon /* Do not reset flow-meter if still in use. */ 310d2185e79SDaniel Machon if (ret > 0) 311d2185e79SDaniel Machon return 0; 312d2185e79SDaniel Machon 313d2185e79SDaniel Machon return sparx5_sdlb_conf_set(sparx5, &fm); 314d2185e79SDaniel Machon } 315