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 struct sparx5_sdlb_group
*sparx5_get_sdlb_group(int idx
)
25 return &sdlb_groups
[idx
];
28 u64
sparx5_sdlb_clk_hz_get(struct sparx5
*sparx5
)
32 clk_hz
= (10 * 1000 * 1000) /
33 (sparx5_clk_period(sparx5
->coreclock
) / 100);
35 return clk_hz
*= 1000;
38 static int sparx5_sdlb_pup_interval_get(struct sparx5
*sparx5
, u32 max_token
,
43 clk_hz
= sparx5_sdlb_clk_hz_get(sparx5
);
45 return div64_u64((8 * clk_hz
* max_token
), max_rate
);
48 int sparx5_sdlb_pup_token_get(struct sparx5
*sparx5
, u32 pup_interval
, u64 rate
)
53 return SPX5_SDLB_PUP_TOKEN_DISABLE
;
55 clk_hz
= sparx5_sdlb_clk_hz_get(sparx5
);
57 return DIV64_U64_ROUND_UP((rate
* pup_interval
), (clk_hz
* 8));
60 static void sparx5_sdlb_group_disable(struct sparx5
*sparx5
, u32 group
)
62 spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(0),
63 ANA_AC_SDLB_PUP_CTRL_PUP_ENA
, sparx5
,
64 ANA_AC_SDLB_PUP_CTRL(group
));
67 static void sparx5_sdlb_group_enable(struct sparx5
*sparx5
, u32 group
)
69 spx5_rmw(ANA_AC_SDLB_PUP_CTRL_PUP_ENA_SET(1),
70 ANA_AC_SDLB_PUP_CTRL_PUP_ENA
, sparx5
,
71 ANA_AC_SDLB_PUP_CTRL(group
));
74 static u32
sparx5_sdlb_group_get_first(struct sparx5
*sparx5
, u32 group
)
78 val
= spx5_rd(sparx5
, ANA_AC_SDLB_XLB_START(group
));
80 return ANA_AC_SDLB_XLB_START_LBSET_START_GET(val
);
83 static u32
sparx5_sdlb_group_get_next(struct sparx5
*sparx5
, u32 group
,
88 val
= spx5_rd(sparx5
, ANA_AC_SDLB_XLB_NEXT(lb
));
90 return ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_GET(val
);
93 static bool sparx5_sdlb_group_is_first(struct sparx5
*sparx5
, u32 group
,
96 return lb
== sparx5_sdlb_group_get_first(sparx5
, group
);
99 static bool sparx5_sdlb_group_is_last(struct sparx5
*sparx5
, u32 group
,
102 return lb
== sparx5_sdlb_group_get_next(sparx5
, group
, lb
);
105 static bool sparx5_sdlb_group_is_empty(struct sparx5
*sparx5
, u32 group
)
109 val
= spx5_rd(sparx5
, ANA_AC_SDLB_PUP_CTRL(group
));
111 return ANA_AC_SDLB_PUP_CTRL_PUP_ENA_GET(val
) == 0;
114 static u32
sparx5_sdlb_group_get_last(struct sparx5
*sparx5
, u32 group
)
118 itr
= sparx5_sdlb_group_get_first(sparx5
, group
);
121 next
= sparx5_sdlb_group_get_next(sparx5
, group
, itr
);
129 static bool sparx5_sdlb_group_is_singular(struct sparx5
*sparx5
, u32 group
)
131 if (sparx5_sdlb_group_is_empty(sparx5
, group
))
134 return sparx5_sdlb_group_get_first(sparx5
, group
) ==
135 sparx5_sdlb_group_get_last(sparx5
, group
);
138 static int sparx5_sdlb_group_get_adjacent(struct sparx5
*sparx5
, u32 group
,
139 u32 idx
, u32
*prev
, u32
*next
,
144 *first
= sparx5_sdlb_group_get_first(sparx5
, group
);
150 *next
= sparx5_sdlb_group_get_next(sparx5
, group
, itr
);
153 return 0; /* Found it */
156 return -EINVAL
; /* Was not found */
163 static int sparx5_sdlb_group_get_count(struct sparx5
*sparx5
, u32 group
)
168 itr
= sparx5_sdlb_group_get_first(sparx5
, group
);
171 next
= sparx5_sdlb_group_get_next(sparx5
, group
, itr
);
180 int sparx5_sdlb_group_get_by_rate(struct sparx5
*sparx5
, u32 rate
, u32 burst
)
182 const struct sparx5_ops
*ops
= sparx5
->data
->ops
;
183 const struct sparx5_sdlb_group
*group
;
187 rate_bps
= rate
* 1000;
189 for (i
= sparx5
->data
->consts
->n_lb_groups
- 1; i
>= 0; i
--) {
190 group
= ops
->get_sdlb_group(i
);
192 count
= sparx5_sdlb_group_get_count(sparx5
, i
);
194 /* Check that this group is not full.
195 * According to LB group configuration rules: the number of XLBs
196 * in a group must not exceed PUP_INTERVAL/4 - 1.
198 if (count
> ((group
->pup_interval
/ 4) - 1))
201 if (rate_bps
< group
->max_rate
)
208 int sparx5_sdlb_group_get_by_index(struct sparx5
*sparx5
, u32 idx
, u32
*group
)
213 for (i
= 0; i
< sparx5
->data
->consts
->n_lb_groups
; i
++) {
214 if (sparx5_sdlb_group_is_empty(sparx5
, i
))
217 itr
= sparx5_sdlb_group_get_first(sparx5
, i
);
220 next
= sparx5_sdlb_group_get_next(sparx5
, i
, itr
);
224 return 0; /* Found it */
227 break; /* Was not found */
236 static int sparx5_sdlb_group_link(struct sparx5
*sparx5
, u32 group
, u32 idx
,
237 u32 first
, u32 next
, bool empty
)
240 sparx5_sdlb_group_disable(sparx5
, group
);
245 /* Link insertion lb to next lb */
246 spx5_wr(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_SET(next
) |
247 ANA_AC_SDLB_XLB_NEXT_LBGRP_SET(group
),
248 sparx5
, ANA_AC_SDLB_XLB_NEXT(idx
));
250 /* Set the first lb */
251 spx5_wr(ANA_AC_SDLB_XLB_START_LBSET_START_SET(first
), sparx5
,
252 ANA_AC_SDLB_XLB_START(group
));
255 sparx5_sdlb_group_enable(sparx5
, group
);
260 int sparx5_sdlb_group_add(struct sparx5
*sparx5
, u32 group
, u32 idx
)
264 /* We always add to head of the list */
267 if (sparx5_sdlb_group_is_empty(sparx5
, group
))
270 next
= sparx5_sdlb_group_get_first(sparx5
, group
);
272 return sparx5_sdlb_group_link(sparx5
, group
, idx
, first
, next
, false);
275 int sparx5_sdlb_group_del(struct sparx5
*sparx5
, u32 group
, u32 idx
)
277 u32 first
, next
, prev
;
280 if (sparx5_sdlb_group_get_adjacent(sparx5
, group
, idx
, &prev
, &next
,
282 pr_err("%s:%d Could not find idx: %d in group: %d", __func__
,
283 __LINE__
, idx
, group
);
287 if (sparx5_sdlb_group_is_singular(sparx5
, group
)) {
289 } else if (sparx5_sdlb_group_is_last(sparx5
, group
, idx
)) {
290 /* idx is removed, prev is now last */
293 } else if (sparx5_sdlb_group_is_first(sparx5
, group
, idx
)) {
294 /* idx is removed and points to itself, first is next */
298 /* Next is not touched */
302 return sparx5_sdlb_group_link(sparx5
, group
, idx
, first
, next
, empty
);
305 void sparx5_sdlb_group_init(struct sparx5
*sparx5
, u64 max_rate
, u32 min_burst
,
306 u32 frame_size
, u32 idx
)
308 const struct sparx5_ops
*ops
= sparx5
->data
->ops
;
309 u32 thres_shift
, mask
= 0x01, power
= 0;
310 struct sparx5_sdlb_group
*group
;
313 group
= ops
->get_sdlb_group(idx
);
315 /* Number of positions to right-shift LB's threshold value. */
316 while ((min_burst
& mask
) == 0) {
320 thres_shift
= SPX5_SDLB_2CYCLES_TYPE2_THRES_OFFSET
- power
;
322 max_token
= (min_burst
> SPX5_SDLB_PUP_TOKEN_MAX
) ?
323 SPX5_SDLB_PUP_TOKEN_MAX
:
325 group
->pup_interval
=
326 sparx5_sdlb_pup_interval_get(sparx5
, max_token
, max_rate
);
328 group
->frame_size
= frame_size
;
330 spx5_wr(ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL_SET(group
->pup_interval
),
331 sparx5
, ANA_AC_SDLB_PUP_INTERVAL(idx
));
333 spx5_wr(ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS_SET(frame_size
),
334 sparx5
, ANA_AC_SDLB_FRM_RATE_TOKENS(idx
));
336 spx5_wr(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT_SET(thres_shift
), sparx5
,
337 ANA_AC_SDLB_LBGRP_MISC(idx
));