1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
4 * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
7 #include "sparx5_main_regs.h"
8 #include "sparx5_main.h"
10 struct sparx5_sdlb_group sdlb_groups[SPX5_SDLB_GROUP_CNT] = {
11 { SPX5_SDLB_GROUP_RATE_MAX, 8192 / 1, 64 }, /* 25 G */
12 { 15000000000ULL, 8192 / 1, 64 }, /* 15 G */
13 { 10000000000ULL, 8192 / 1, 64 }, /* 10 G */
14 { 5000000000ULL, 8192 / 1, 64 }, /* 5 G */
15 { 2500000000ULL, 8192 / 1, 64 }, /* 2.5 G */
16 { 1000000000ULL, 8192 / 2, 64 }, /* 1 G */
17 { 500000000ULL, 8192 / 2, 64 }, /* 500 M */
18 { 100000000ULL, 8192 / 4, 64 }, /* 100 M */
19 { 50000000ULL, 8192 / 4, 64 }, /* 50 M */
20 { 5000000ULL, 8192 / 8, 64 } /* 5 M */
23 int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5)
28 clk_per_100ps = HSCH_SYS_CLK_PER_100PS_GET(spx5_rd(sparx5,
31 clk_per_100ps = SPX5_CLK_PER_100PS_DEFAULT;
33 clk_hz = (10 * 1000 * 1000) / clk_per_100ps;
34 return clk_hz *= 1000;
37 static int sparx5_sdlb_pup_interval_get(struct sparx5 *sparx5, u32 max_token,
42 clk_hz = sparx5_sdlb_clk_hz_get(sparx5);
44 return div64_u64((8 * clk_hz * max_token), max_rate);
47 int sparx5_sdlb_pup_token_get(struct sparx5 *sparx5, u32 pup_interval, u64 rate)
52 return SPX5_SDLB_PUP_TOKEN_DISABLE;
54 clk_hz = sparx5_sdlb_clk_hz_get(sparx5);
56 return DIV64_U64_ROUND_UP((rate * pup_interval), (clk_hz * 8));
59 static void sparx5_sdlb_group_disable(struct sparx5 *sparx5, u32 group)
61 spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(0),
62 ANA_AC_SDLB_PUP_CTRL_PUP_ENA, sparx5,
63 ANA_AC_SDLB_PUP_CTRL(group));
66 static void sparx5_sdlb_group_enable(struct sparx5 *sparx5, u32 group)
68 spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(1),
69 ANA_AC_SDLB_PUP_CTRL_PUP_ENA, sparx5,
70 ANA_AC_SDLB_PUP_CTRL(group));
73 static u32 sparx5_sdlb_group_get_first(struct sparx5 *sparx5, u32 group)
77 val = spx5_rd(sparx5, ANA_AC_SDLB_XLB_START(group));
79 return ANA_AC_SDLB_XLB_START_LBSET_START_GET(val);
82 static u32 sparx5_sdlb_group_get_next(struct sparx5 *sparx5, u32 group,
87 val = spx5_rd(sparx5, ANA_AC_SDLB_XLB_NEXT(lb));
89 return ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_GET(val);
92 static bool sparx5_sdlb_group_is_first(struct sparx5 *sparx5, u32 group,
95 return lb == sparx5_sdlb_group_get_first(sparx5, group);
98 static bool sparx5_sdlb_group_is_last(struct sparx5 *sparx5, u32 group,
101 return lb == sparx5_sdlb_group_get_next(sparx5, group, lb);
104 static bool sparx5_sdlb_group_is_empty(struct sparx5 *sparx5, u32 group)
108 val = spx5_rd(sparx5, ANA_AC_SDLB_PUP_CTRL(group));
110 return ANA_AC_SDLB_PUP_CTRL_PUP_ENA_GET(val) == 0;
113 static u32 sparx5_sdlb_group_get_last(struct sparx5 *sparx5, u32 group)
117 itr = sparx5_sdlb_group_get_first(sparx5, group);
120 next = sparx5_sdlb_group_get_next(sparx5, group, itr);
128 static bool sparx5_sdlb_group_is_singular(struct sparx5 *sparx5, u32 group)
130 if (sparx5_sdlb_group_is_empty(sparx5, group))
133 return sparx5_sdlb_group_get_first(sparx5, group) ==
134 sparx5_sdlb_group_get_last(sparx5, group);
137 static int sparx5_sdlb_group_get_adjacent(struct sparx5 *sparx5, u32 group,
138 u32 idx, u32 *prev, u32 *next,
143 *first = sparx5_sdlb_group_get_first(sparx5, group);
149 *next = sparx5_sdlb_group_get_next(sparx5, group, itr);
152 return 0; /* Found it */
155 return -EINVAL; /* Was not found */
162 static int sparx5_sdlb_group_get_count(struct sparx5 *sparx5, u32 group)
167 itr = sparx5_sdlb_group_get_first(sparx5, group);
170 next = sparx5_sdlb_group_get_next(sparx5, group, itr);
179 int sparx5_sdlb_group_get_by_rate(struct sparx5 *sparx5, u32 rate, u32 burst)
181 const struct sparx5_sdlb_group *group;
185 rate_bps = rate * 1000;
187 for (i = SPX5_SDLB_GROUP_CNT - 1; i >= 0; i--) {
188 group = &sdlb_groups[i];
190 count = sparx5_sdlb_group_get_count(sparx5, i);
192 /* Check that this group is not full.
193 * According to LB group configuration rules: the number of XLBs
194 * in a group must not exceed PUP_INTERVAL/4 - 1.
196 if (count > ((group->pup_interval / 4) - 1))
199 if (rate_bps < group->max_rate)
206 int sparx5_sdlb_group_get_by_index(struct sparx5 *sparx5, u32 idx, u32 *group)
211 for (i = 0; i < SPX5_SDLB_GROUP_CNT; i++) {
212 if (sparx5_sdlb_group_is_empty(sparx5, i))
215 itr = sparx5_sdlb_group_get_first(sparx5, i);
218 next = sparx5_sdlb_group_get_next(sparx5, i, itr);
222 return 0; /* Found it */
225 break; /* Was not found */
234 static int sparx5_sdlb_group_link(struct sparx5 *sparx5, u32 group, u32 idx,
235 u32 first, u32 next, bool empty)
238 sparx5_sdlb_group_disable(sparx5, group);
243 /* Link insertion lb to next lb */
244 spx5_wr(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_SET(next) |
245 ANA_AC_SDLB_XLB_NEXT_LBGRP_SET(group),
246 sparx5, ANA_AC_SDLB_XLB_NEXT(idx));
248 /* Set the first lb */
249 spx5_wr(ANA_AC_SDLB_XLB_START_LBSET_START_SET(first), sparx5,
250 ANA_AC_SDLB_XLB_START(group));
253 sparx5_sdlb_group_enable(sparx5, group);
258 int sparx5_sdlb_group_add(struct sparx5 *sparx5, u32 group, u32 idx)
262 /* We always add to head of the list */
265 if (sparx5_sdlb_group_is_empty(sparx5, group))
268 next = sparx5_sdlb_group_get_first(sparx5, group);
270 return sparx5_sdlb_group_link(sparx5, group, idx, first, next, false);
273 int sparx5_sdlb_group_del(struct sparx5 *sparx5, u32 group, u32 idx)
275 u32 first, next, prev;
278 if (sparx5_sdlb_group_get_adjacent(sparx5, group, idx, &prev, &next,
280 pr_err("%s:%d Could not find idx: %d in group: %d", __func__,
281 __LINE__, idx, group);
285 if (sparx5_sdlb_group_is_singular(sparx5, group)) {
287 } else if (sparx5_sdlb_group_is_last(sparx5, group, idx)) {
288 /* idx is removed, prev is now last */
291 } else if (sparx5_sdlb_group_is_first(sparx5, group, idx)) {
292 /* idx is removed and points to itself, first is next */
296 /* Next is not touched */
300 return sparx5_sdlb_group_link(sparx5, group, idx, first, next, empty);
303 void sparx5_sdlb_group_init(struct sparx5 *sparx5, u64 max_rate, u32 min_burst,
304 u32 frame_size, u32 idx)
306 u32 thres_shift, mask = 0x01, power = 0;
307 struct sparx5_sdlb_group *group;
310 group = &sdlb_groups[idx];
312 /* Number of positions to right-shift LB's threshold value. */
313 while ((min_burst & mask) == 0) {
317 thres_shift = SPX5_SDLB_2CYCLES_TYPE2_THRES_OFFSET - power;
319 max_token = (min_burst > SPX5_SDLB_PUP_TOKEN_MAX) ?
320 SPX5_SDLB_PUP_TOKEN_MAX :
322 group->pup_interval =
323 sparx5_sdlb_pup_interval_get(sparx5, max_token, max_rate);
325 group->frame_size = frame_size;
327 spx5_wr(ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL_SET(group->pup_interval),
328 sparx5, ANA_AC_SDLB_PUP_INTERVAL(idx));
330 spx5_wr(ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS_SET(frame_size),
331 sparx5, ANA_AC_SDLB_FRM_RATE_TOKENS(idx));
333 spx5_wr(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT_SET(thres_shift), sparx5,
334 ANA_AC_SDLB_LBGRP_MISC(idx));