Commit | Line | Data |
---|---|---|
9948a064 JP |
1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ | |
56ade8fe JP |
3 | |
4 | #include <linux/kernel.h> | |
5 | #include <linux/types.h> | |
dd6cb0f9 | 6 | #include <linux/dcbnl.h> |
ff6551ec | 7 | #include <linux/if_ether.h> |
2d0ed39f | 8 | #include <linux/list.h> |
8f686206 | 9 | #include <linux/netlink.h> |
56ade8fe JP |
10 | |
11 | #include "spectrum.h" | |
12 | #include "core.h" | |
13 | #include "port.h" | |
14 | #include "reg.h" | |
15 | ||
33cbd87c IS |
16 | struct mlxsw_sp_sb_pr { |
17 | enum mlxsw_reg_sbpr_mode mode; | |
18 | u32 size; | |
0636f4de IS |
19 | u8 freeze_mode:1, |
20 | freeze_size:1; | |
33cbd87c IS |
21 | }; |
22 | ||
23 | struct mlxsw_cp_sb_occ { | |
24 | u32 cur; | |
25 | u32 max; | |
26 | }; | |
27 | ||
28 | struct mlxsw_sp_sb_cm { | |
29 | u32 min_buff; | |
30 | u32 max_buff; | |
3a4dbfb0 | 31 | u16 pool_index; |
33cbd87c | 32 | struct mlxsw_cp_sb_occ occ; |
f7936d0b IS |
33 | u8 freeze_pool:1, |
34 | freeze_thresh:1; | |
33cbd87c IS |
35 | }; |
36 | ||
f0024f0d | 37 | #define MLXSW_SP_SB_INFI -1U |
bc9f6e94 | 38 | #define MLXSW_SP_SB_REST -2U |
f0024f0d | 39 | |
33cbd87c IS |
40 | struct mlxsw_sp_sb_pm { |
41 | u32 min_buff; | |
42 | u32 max_buff; | |
43 | struct mlxsw_cp_sb_occ occ; | |
44 | }; | |
45 | ||
13f35cc4 PM |
46 | struct mlxsw_sp_sb_mm { |
47 | u32 min_buff; | |
48 | u32 max_buff; | |
49 | u16 pool_index; | |
50 | }; | |
51 | ||
3a4dbfb0 PM |
52 | struct mlxsw_sp_sb_pool_des { |
53 | enum mlxsw_reg_sbxx_dir dir; | |
54 | u8 pool; | |
55 | }; | |
56 | ||
93d3668c | 57 | #define MLXSW_SP_SB_POOL_ING 0 |
93d3668c IS |
58 | #define MLXSW_SP_SB_POOL_EGR 4 |
59 | #define MLXSW_SP_SB_POOL_EGR_MC 8 | |
265c49b4 IS |
60 | #define MLXSW_SP_SB_POOL_ING_CPU 9 |
61 | #define MLXSW_SP_SB_POOL_EGR_CPU 10 | |
93d3668c | 62 | |
fe099bf6 | 63 | static const struct mlxsw_sp_sb_pool_des mlxsw_sp1_sb_pool_dess[] = { |
3a4dbfb0 PM |
64 | {MLXSW_REG_SBXX_DIR_INGRESS, 0}, |
65 | {MLXSW_REG_SBXX_DIR_INGRESS, 1}, | |
66 | {MLXSW_REG_SBXX_DIR_INGRESS, 2}, | |
67 | {MLXSW_REG_SBXX_DIR_INGRESS, 3}, | |
68 | {MLXSW_REG_SBXX_DIR_EGRESS, 0}, | |
69 | {MLXSW_REG_SBXX_DIR_EGRESS, 1}, | |
70 | {MLXSW_REG_SBXX_DIR_EGRESS, 2}, | |
71 | {MLXSW_REG_SBXX_DIR_EGRESS, 3}, | |
72 | {MLXSW_REG_SBXX_DIR_EGRESS, 15}, | |
265c49b4 IS |
73 | {MLXSW_REG_SBXX_DIR_INGRESS, 4}, |
74 | {MLXSW_REG_SBXX_DIR_EGRESS, 4}, | |
3a4dbfb0 PM |
75 | }; |
76 | ||
fe099bf6 PM |
77 | static const struct mlxsw_sp_sb_pool_des mlxsw_sp2_sb_pool_dess[] = { |
78 | {MLXSW_REG_SBXX_DIR_INGRESS, 0}, | |
79 | {MLXSW_REG_SBXX_DIR_INGRESS, 1}, | |
80 | {MLXSW_REG_SBXX_DIR_INGRESS, 2}, | |
81 | {MLXSW_REG_SBXX_DIR_INGRESS, 3}, | |
82 | {MLXSW_REG_SBXX_DIR_EGRESS, 0}, | |
83 | {MLXSW_REG_SBXX_DIR_EGRESS, 1}, | |
84 | {MLXSW_REG_SBXX_DIR_EGRESS, 2}, | |
85 | {MLXSW_REG_SBXX_DIR_EGRESS, 3}, | |
d5949d92 | 86 | {MLXSW_REG_SBXX_DIR_EGRESS, 15}, |
265c49b4 IS |
87 | {MLXSW_REG_SBXX_DIR_INGRESS, 4}, |
88 | {MLXSW_REG_SBXX_DIR_EGRESS, 4}, | |
fe099bf6 PM |
89 | }; |
90 | ||
5f95d20b PM |
91 | #define MLXSW_SP_SB_ING_TC_COUNT 8 |
92 | #define MLXSW_SP_SB_EG_TC_COUNT 16 | |
33cbd87c IS |
93 | |
94 | struct mlxsw_sp_sb_port { | |
5f95d20b PM |
95 | struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT]; |
96 | struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT]; | |
93d201f7 | 97 | struct mlxsw_sp_sb_pm *pms; |
33cbd87c IS |
98 | }; |
99 | ||
100 | struct mlxsw_sp_sb { | |
93d201f7 | 101 | struct mlxsw_sp_sb_pr *prs; |
33cbd87c IS |
102 | struct mlxsw_sp_sb_port *ports; |
103 | u32 cell_size; | |
bb6c346c | 104 | u32 max_headroom_cells; |
fe07d723 | 105 | u64 sb_size; |
33cbd87c IS |
106 | }; |
107 | ||
c39f3e0e | 108 | struct mlxsw_sp_sb_vals { |
5d65f5f4 PM |
109 | unsigned int pool_count; |
110 | const struct mlxsw_sp_sb_pool_des *pool_dess; | |
cc1ce6ff | 111 | const struct mlxsw_sp_sb_pm *pms; |
7a1ff9f4 | 112 | const struct mlxsw_sp_sb_pm *pms_cpu; |
5d25232e | 113 | const struct mlxsw_sp_sb_pr *prs; |
13f35cc4 | 114 | const struct mlxsw_sp_sb_mm *mms; |
bb60a62e PM |
115 | const struct mlxsw_sp_sb_cm *cms_ingress; |
116 | const struct mlxsw_sp_sb_cm *cms_egress; | |
117 | const struct mlxsw_sp_sb_cm *cms_cpu; | |
13f35cc4 | 118 | unsigned int mms_count; |
bb60a62e PM |
119 | unsigned int cms_ingress_count; |
120 | unsigned int cms_egress_count; | |
121 | unsigned int cms_cpu_count; | |
c39f3e0e PM |
122 | }; |
123 | ||
33cbd87c IS |
124 | u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) |
125 | { | |
126 | return mlxsw_sp->sb->cell_size * cells; | |
127 | } | |
128 | ||
129 | u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) | |
130 | { | |
131 | return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size); | |
132 | } | |
133 | ||
078f9c71 | 134 | static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, |
3a4dbfb0 | 135 | u16 pool_index) |
078f9c71 | 136 | { |
3a4dbfb0 | 137 | return &mlxsw_sp->sb->prs[pool_index]; |
078f9c71 JP |
138 | } |
139 | ||
5f95d20b PM |
140 | static bool mlxsw_sp_sb_cm_exists(u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) |
141 | { | |
142 | if (dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
143 | return pg_buff < MLXSW_SP_SB_ING_TC_COUNT; | |
144 | else | |
145 | return pg_buff < MLXSW_SP_SB_EG_TC_COUNT; | |
146 | } | |
147 | ||
078f9c71 JP |
148 | static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, |
149 | u8 local_port, u8 pg_buff, | |
150 | enum mlxsw_reg_sbxx_dir dir) | |
151 | { | |
5f95d20b PM |
152 | struct mlxsw_sp_sb_port *sb_port = &mlxsw_sp->sb->ports[local_port]; |
153 | ||
154 | WARN_ON(!mlxsw_sp_sb_cm_exists(pg_buff, dir)); | |
155 | if (dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
156 | return &sb_port->ing_cms[pg_buff]; | |
157 | else | |
158 | return &sb_port->eg_cms[pg_buff]; | |
078f9c71 JP |
159 | } |
160 | ||
161 | static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, | |
3a4dbfb0 | 162 | u8 local_port, u16 pool_index) |
078f9c71 | 163 | { |
3a4dbfb0 | 164 | return &mlxsw_sp->sb->ports[local_port].pms[pool_index]; |
078f9c71 JP |
165 | } |
166 | ||
3a4dbfb0 | 167 | static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index, |
f0024f0d PM |
168 | enum mlxsw_reg_sbpr_mode mode, |
169 | u32 size, bool infi_size) | |
94266e32 | 170 | { |
3a4dbfb0 | 171 | const struct mlxsw_sp_sb_pool_des *des = |
5d65f5f4 | 172 | &mlxsw_sp->sb_vals->pool_dess[pool_index]; |
94266e32 | 173 | char sbpr_pl[MLXSW_REG_SBPR_LEN]; |
078f9c71 JP |
174 | struct mlxsw_sp_sb_pr *pr; |
175 | int err; | |
94266e32 | 176 | |
f0024f0d PM |
177 | mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode, |
178 | size, infi_size); | |
078f9c71 JP |
179 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl); |
180 | if (err) | |
181 | return err; | |
182 | ||
f0024f0d PM |
183 | if (infi_size) |
184 | size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp->sb->sb_size); | |
3a4dbfb0 | 185 | pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); |
078f9c71 JP |
186 | pr->mode = mode; |
187 | pr->size = size; | |
188 | return 0; | |
94266e32 JP |
189 | } |
190 | ||
191 | static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |
3a4dbfb0 | 192 | u8 pg_buff, u32 min_buff, u32 max_buff, |
d144e3a2 | 193 | bool infi_max, u16 pool_index) |
94266e32 | 194 | { |
3a4dbfb0 | 195 | const struct mlxsw_sp_sb_pool_des *des = |
5d65f5f4 | 196 | &mlxsw_sp->sb_vals->pool_dess[pool_index]; |
94266e32 | 197 | char sbcm_pl[MLXSW_REG_SBCM_LEN]; |
d144e3a2 | 198 | struct mlxsw_sp_sb_cm *cm; |
078f9c71 | 199 | int err; |
94266e32 | 200 | |
3a4dbfb0 | 201 | mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir, |
d144e3a2 | 202 | min_buff, max_buff, infi_max, des->pool); |
078f9c71 JP |
203 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl); |
204 | if (err) | |
205 | return err; | |
d144e3a2 | 206 | |
5f95d20b | 207 | if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) { |
d144e3a2 PM |
208 | if (infi_max) |
209 | max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, | |
210 | mlxsw_sp->sb->sb_size); | |
078f9c71 | 211 | |
3a4dbfb0 PM |
212 | cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, |
213 | des->dir); | |
078f9c71 JP |
214 | cm->min_buff = min_buff; |
215 | cm->max_buff = max_buff; | |
3a4dbfb0 | 216 | cm->pool_index = pool_index; |
078f9c71 JP |
217 | } |
218 | return 0; | |
94266e32 JP |
219 | } |
220 | ||
221 | static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |
3a4dbfb0 | 222 | u16 pool_index, u32 min_buff, u32 max_buff) |
94266e32 | 223 | { |
3a4dbfb0 | 224 | const struct mlxsw_sp_sb_pool_des *des = |
5d65f5f4 | 225 | &mlxsw_sp->sb_vals->pool_dess[pool_index]; |
94266e32 | 226 | char sbpm_pl[MLXSW_REG_SBPM_LEN]; |
078f9c71 JP |
227 | struct mlxsw_sp_sb_pm *pm; |
228 | int err; | |
94266e32 | 229 | |
3a4dbfb0 | 230 | mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, false, |
42a7f1d7 | 231 | min_buff, max_buff); |
078f9c71 JP |
232 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl); |
233 | if (err) | |
234 | return err; | |
235 | ||
3a4dbfb0 | 236 | pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); |
078f9c71 JP |
237 | pm->min_buff = min_buff; |
238 | pm->max_buff = max_buff; | |
239 | return 0; | |
94266e32 JP |
240 | } |
241 | ||
2d0ed39f | 242 | static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port, |
3a4dbfb0 | 243 | u16 pool_index, struct list_head *bulk_list) |
2d0ed39f | 244 | { |
3a4dbfb0 | 245 | const struct mlxsw_sp_sb_pool_des *des = |
5d65f5f4 | 246 | &mlxsw_sp->sb_vals->pool_dess[pool_index]; |
2d0ed39f JP |
247 | char sbpm_pl[MLXSW_REG_SBPM_LEN]; |
248 | ||
a759ab6d ST |
249 | if (local_port == MLXSW_PORT_CPU_PORT && |
250 | des->dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
251 | return 0; | |
252 | ||
3a4dbfb0 PM |
253 | mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, |
254 | true, 0, 0); | |
2d0ed39f JP |
255 | return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, |
256 | bulk_list, NULL, 0); | |
257 | } | |
258 | ||
259 | static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core, | |
260 | char *sbpm_pl, size_t sbpm_pl_len, | |
261 | unsigned long cb_priv) | |
262 | { | |
263 | struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv; | |
264 | ||
265 | mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max); | |
266 | } | |
267 | ||
268 | static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port, | |
3a4dbfb0 | 269 | u16 pool_index, struct list_head *bulk_list) |
2d0ed39f | 270 | { |
3a4dbfb0 | 271 | const struct mlxsw_sp_sb_pool_des *des = |
5d65f5f4 | 272 | &mlxsw_sp->sb_vals->pool_dess[pool_index]; |
2d0ed39f JP |
273 | char sbpm_pl[MLXSW_REG_SBPM_LEN]; |
274 | struct mlxsw_sp_sb_pm *pm; | |
275 | ||
a759ab6d ST |
276 | if (local_port == MLXSW_PORT_CPU_PORT && |
277 | des->dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
278 | return 0; | |
279 | ||
3a4dbfb0 PM |
280 | pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index); |
281 | mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, | |
282 | false, 0, 0); | |
2d0ed39f JP |
283 | return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl, |
284 | bulk_list, | |
285 | mlxsw_sp_sb_pm_occ_query_cb, | |
286 | (unsigned long) pm); | |
287 | } | |
288 | ||
edf777f5 PM |
289 | /* 1/4 of a headroom necessary for 100Gbps port and 100m cable. */ |
290 | #define MLXSW_SP_PB_HEADROOM 25632 | |
b94cdabb | 291 | #define MLXSW_SP_PB_UNUSED 8 |
56ade8fe JP |
292 | |
293 | static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port) | |
294 | { | |
edf777f5 PM |
295 | const u32 pbs[] = { |
296 | [0] = MLXSW_SP_PB_HEADROOM * mlxsw_sp_port->mapping.width, | |
50b5b905 | 297 | [9] = MLXSW_PORT_MAX_MTU, |
edf777f5 | 298 | }; |
18281f2d | 299 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
56ade8fe JP |
300 | char pbmc_pl[MLXSW_REG_PBMC_LEN]; |
301 | int i; | |
302 | ||
303 | mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, | |
304 | 0xffff, 0xffff / 2); | |
edf777f5 PM |
305 | for (i = 0; i < ARRAY_SIZE(pbs); i++) { |
306 | u16 size = mlxsw_sp_bytes_cells(mlxsw_sp, pbs[i]); | |
18281f2d | 307 | |
b94cdabb | 308 | if (i == MLXSW_SP_PB_UNUSED) |
b11c3b40 | 309 | continue; |
f3fe412b | 310 | size = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, size); |
18281f2d | 311 | mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, i, size); |
56ade8fe | 312 | } |
d6b7c13b IS |
313 | mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, |
314 | MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0); | |
18281f2d | 315 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl); |
56ade8fe JP |
316 | } |
317 | ||
dd6cb0f9 IS |
318 | static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port *mlxsw_sp_port) |
319 | { | |
320 | char pptb_pl[MLXSW_REG_PPTB_LEN]; | |
321 | int i; | |
322 | ||
323 | mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); | |
324 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | |
11719a58 | 325 | mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, i, 0); |
dd6cb0f9 IS |
326 | return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), |
327 | pptb_pl); | |
328 | } | |
329 | ||
5df825ed PM |
330 | void mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom *hdroom) |
331 | { | |
332 | int prio; | |
333 | ||
334 | for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) | |
335 | hdroom->prios.prio[prio].buf_idx = hdroom->prios.prio[prio].ets_buf_idx; | |
336 | } | |
337 | ||
ca21e84e PM |
338 | void mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom *hdroom) |
339 | { | |
340 | int prio; | |
341 | int i; | |
342 | ||
343 | for (i = 0; i < DCBX_MAX_BUFFERS; i++) | |
344 | hdroom->bufs.buf[i].lossy = true; | |
345 | ||
346 | for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++) { | |
347 | if (!hdroom->prios.prio[prio].lossy) | |
348 | hdroom->bufs.buf[hdroom->prios.prio[prio].buf_idx].lossy = false; | |
349 | } | |
350 | } | |
351 | ||
4c22f29f PM |
352 | static u16 mlxsw_sp_hdroom_buf_threshold_get(const struct mlxsw_sp *mlxsw_sp, int mtu) |
353 | { | |
354 | return 2 * mlxsw_sp_bytes_cells(mlxsw_sp, mtu); | |
355 | } | |
356 | ||
357 | static void mlxsw_sp_hdroom_buf_pack(char *pbmc_pl, int index, u16 size, u16 thres, bool lossy) | |
358 | { | |
359 | if (lossy) | |
360 | mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, index, size); | |
361 | else | |
362 | mlxsw_reg_pbmc_lossless_buffer_pack(pbmc_pl, index, size, | |
363 | thres); | |
364 | } | |
365 | ||
366 | static u16 mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp *mlxsw_sp, | |
367 | const struct mlxsw_sp_hdroom *hdroom) | |
368 | { | |
369 | u16 delay_cells; | |
370 | ||
371 | delay_cells = mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->delay_bytes); | |
372 | ||
373 | /* In the worst case scenario the delay will be made up of packets that | |
374 | * are all of size CELL_SIZE + 1, which means each packet will require | |
375 | * almost twice its true size when buffered in the switch. We therefore | |
376 | * multiply this value by the "cell factor", which is close to 2. | |
377 | * | |
378 | * Another MTU is added in case the transmitting host already started | |
379 | * transmitting a maximum length frame when the PFC packet was received. | |
380 | */ | |
381 | return 2 * delay_cells + mlxsw_sp_bytes_cells(mlxsw_sp, hdroom->mtu); | |
382 | } | |
383 | ||
384 | static bool mlxsw_sp_hdroom_buf_is_used(const struct mlxsw_sp_hdroom *hdroom, int buf) | |
385 | { | |
386 | int prio; | |
387 | ||
388 | for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) { | |
389 | if (hdroom->prios.prio[prio].buf_idx == buf) | |
390 | return true; | |
391 | } | |
392 | return false; | |
393 | } | |
394 | ||
395 | void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port, | |
396 | struct mlxsw_sp_hdroom *hdroom) | |
397 | { | |
398 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
399 | int i; | |
400 | ||
401 | for (i = 0; i < DCBX_MAX_BUFFERS; i++) { | |
402 | struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i]; | |
403 | u16 thres_cells; | |
404 | u16 delay_cells; | |
405 | ||
406 | if (!mlxsw_sp_hdroom_buf_is_used(hdroom, i)) { | |
407 | thres_cells = 0; | |
408 | delay_cells = 0; | |
409 | } else if (buf->lossy) { | |
410 | thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu); | |
411 | delay_cells = 0; | |
412 | } else { | |
413 | thres_cells = mlxsw_sp_hdroom_buf_threshold_get(mlxsw_sp, hdroom->mtu); | |
414 | delay_cells = mlxsw_sp_hdroom_buf_delay_get(mlxsw_sp, hdroom); | |
415 | } | |
416 | ||
417 | thres_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, thres_cells); | |
418 | delay_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, delay_cells); | |
419 | ||
420 | buf->thres_cells = thres_cells; | |
421 | buf->size_cells = thres_cells + delay_cells; | |
422 | } | |
423 | } | |
424 | ||
425 | static int mlxsw_sp_hdroom_configure_buffers(struct mlxsw_sp_port *mlxsw_sp_port, | |
426 | const struct mlxsw_sp_hdroom *hdroom, bool force) | |
427 | { | |
428 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
429 | char pbmc_pl[MLXSW_REG_PBMC_LEN]; | |
430 | bool dirty; | |
431 | int err; | |
432 | int i; | |
433 | ||
434 | dirty = memcmp(&mlxsw_sp_port->hdroom->bufs, &hdroom->bufs, sizeof(hdroom->bufs)); | |
435 | if (!dirty && !force) | |
436 | return 0; | |
437 | ||
438 | mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 0, 0); | |
439 | err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl); | |
440 | if (err) | |
441 | return err; | |
442 | ||
443 | for (i = 0; i < DCBX_MAX_BUFFERS; i++) { | |
444 | const struct mlxsw_sp_hdroom_buf *buf = &hdroom->bufs.buf[i]; | |
445 | ||
446 | mlxsw_sp_hdroom_buf_pack(pbmc_pl, i, buf->size_cells, buf->thres_cells, buf->lossy); | |
447 | } | |
448 | ||
449 | mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0); | |
450 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl); | |
451 | if (err) | |
452 | return err; | |
453 | ||
454 | mlxsw_sp_port->hdroom->bufs = hdroom->bufs; | |
455 | return 0; | |
456 | } | |
457 | ||
458 | static int mlxsw_sp_hdroom_configure_priomap(struct mlxsw_sp_port *mlxsw_sp_port, | |
459 | const struct mlxsw_sp_hdroom *hdroom, bool force) | |
460 | { | |
461 | char pptb_pl[MLXSW_REG_PPTB_LEN]; | |
462 | bool dirty; | |
463 | int prio; | |
464 | int err; | |
465 | ||
466 | dirty = memcmp(&mlxsw_sp_port->hdroom->prios, &hdroom->prios, sizeof(hdroom->prios)); | |
467 | if (!dirty && !force) | |
468 | return 0; | |
469 | ||
470 | mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); | |
471 | for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) | |
472 | mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, prio, hdroom->prios.prio[prio].buf_idx); | |
473 | ||
474 | err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl); | |
475 | if (err) | |
476 | return err; | |
477 | ||
478 | mlxsw_sp_port->hdroom->prios = hdroom->prios; | |
479 | return 0; | |
480 | } | |
481 | ||
482 | static bool mlxsw_sp_hdroom_bufs_fit(struct mlxsw_sp *mlxsw_sp, | |
483 | const struct mlxsw_sp_hdroom *hdroom) | |
484 | { | |
485 | u32 taken_headroom_cells = 0; | |
4c22f29f PM |
486 | int i; |
487 | ||
488 | for (i = 0; i < MLXSW_SP_PB_COUNT; i++) | |
489 | taken_headroom_cells += hdroom->bufs.buf[i].size_cells; | |
490 | ||
bd3e86a5 | 491 | return taken_headroom_cells <= mlxsw_sp->sb->max_headroom_cells; |
4c22f29f PM |
492 | } |
493 | ||
494 | static int __mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, | |
495 | const struct mlxsw_sp_hdroom *hdroom, bool force) | |
496 | { | |
497 | struct mlxsw_sp_hdroom orig_hdroom; | |
498 | struct mlxsw_sp_hdroom tmp_hdroom; | |
499 | int err; | |
500 | int i; | |
501 | ||
502 | /* Port buffers need to be configured in three steps. First, all buffers | |
503 | * with non-zero size are configured. Then, prio-to-buffer map is | |
504 | * updated, allowing traffic to flow to the now non-zero buffers. | |
505 | * Finally, zero-sized buffers are configured, because now no traffic | |
506 | * should be directed to them anymore. This way, in a non-congested | |
507 | * system, no packet drops are introduced by the reconfiguration. | |
508 | */ | |
509 | ||
510 | orig_hdroom = *mlxsw_sp_port->hdroom; | |
511 | tmp_hdroom = orig_hdroom; | |
512 | for (i = 0; i < MLXSW_SP_PB_COUNT; i++) { | |
513 | if (hdroom->bufs.buf[i].size_cells) | |
514 | tmp_hdroom.bufs.buf[i] = hdroom->bufs.buf[i]; | |
515 | } | |
516 | ||
517 | if (!mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, &tmp_hdroom) || | |
518 | !mlxsw_sp_hdroom_bufs_fit(mlxsw_sp_port->mlxsw_sp, hdroom)) | |
519 | return -ENOBUFS; | |
520 | ||
521 | err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &tmp_hdroom, force); | |
522 | if (err) | |
523 | return err; | |
524 | ||
525 | err = mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, hdroom, force); | |
526 | if (err) | |
527 | goto err_configure_priomap; | |
528 | ||
529 | err = mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, hdroom, false); | |
530 | if (err) | |
531 | goto err_configure_buffers; | |
532 | ||
533 | *mlxsw_sp_port->hdroom = *hdroom; | |
534 | return 0; | |
535 | ||
536 | err_configure_buffers: | |
537 | mlxsw_sp_hdroom_configure_priomap(mlxsw_sp_port, &tmp_hdroom, false); | |
538 | err_configure_priomap: | |
539 | mlxsw_sp_hdroom_configure_buffers(mlxsw_sp_port, &orig_hdroom, false); | |
540 | return err; | |
541 | } | |
542 | ||
543 | int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port, | |
544 | const struct mlxsw_sp_hdroom *hdroom) | |
545 | { | |
546 | return __mlxsw_sp_hdroom_configure(mlxsw_sp_port, hdroom, false); | |
547 | } | |
548 | ||
dd6cb0f9 IS |
549 | static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port) |
550 | { | |
551 | int err; | |
552 | ||
553 | err = mlxsw_sp_port_pb_init(mlxsw_sp_port); | |
554 | if (err) | |
555 | return err; | |
556 | return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port); | |
557 | } | |
558 | ||
93d201f7 PM |
559 | static int mlxsw_sp_sb_port_init(struct mlxsw_sp *mlxsw_sp, |
560 | struct mlxsw_sp_sb_port *sb_port) | |
561 | { | |
562 | struct mlxsw_sp_sb_pm *pms; | |
563 | ||
5d65f5f4 PM |
564 | pms = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*pms), |
565 | GFP_KERNEL); | |
93d201f7 PM |
566 | if (!pms) |
567 | return -ENOMEM; | |
568 | sb_port->pms = pms; | |
569 | return 0; | |
570 | } | |
571 | ||
572 | static void mlxsw_sp_sb_port_fini(struct mlxsw_sp_sb_port *sb_port) | |
573 | { | |
574 | kfree(sb_port->pms); | |
575 | } | |
576 | ||
5ec2ee7d IS |
577 | static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp) |
578 | { | |
579 | unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); | |
93d201f7 PM |
580 | struct mlxsw_sp_sb_pr *prs; |
581 | int i; | |
582 | int err; | |
5ec2ee7d | 583 | |
33cbd87c IS |
584 | mlxsw_sp->sb->ports = kcalloc(max_ports, |
585 | sizeof(struct mlxsw_sp_sb_port), | |
586 | GFP_KERNEL); | |
587 | if (!mlxsw_sp->sb->ports) | |
5ec2ee7d | 588 | return -ENOMEM; |
93d201f7 | 589 | |
5d65f5f4 PM |
590 | prs = kcalloc(mlxsw_sp->sb_vals->pool_count, sizeof(*prs), |
591 | GFP_KERNEL); | |
93d201f7 PM |
592 | if (!prs) { |
593 | err = -ENOMEM; | |
594 | goto err_alloc_prs; | |
595 | } | |
596 | mlxsw_sp->sb->prs = prs; | |
597 | ||
598 | for (i = 0; i < max_ports; i++) { | |
599 | err = mlxsw_sp_sb_port_init(mlxsw_sp, &mlxsw_sp->sb->ports[i]); | |
600 | if (err) | |
601 | goto err_sb_port_init; | |
602 | } | |
603 | ||
5ec2ee7d | 604 | return 0; |
93d201f7 PM |
605 | |
606 | err_sb_port_init: | |
607 | for (i--; i >= 0; i--) | |
608 | mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]); | |
609 | kfree(mlxsw_sp->sb->prs); | |
610 | err_alloc_prs: | |
611 | kfree(mlxsw_sp->sb->ports); | |
612 | return err; | |
5ec2ee7d IS |
613 | } |
614 | ||
615 | static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) | |
616 | { | |
93d201f7 PM |
617 | int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); |
618 | int i; | |
619 | ||
620 | for (i = max_ports - 1; i >= 0; i--) | |
621 | mlxsw_sp_sb_port_fini(&mlxsw_sp->sb->ports[i]); | |
622 | kfree(mlxsw_sp->sb->prs); | |
33cbd87c | 623 | kfree(mlxsw_sp->sb->ports); |
5ec2ee7d IS |
624 | } |
625 | ||
aa99bc70 | 626 | #define MLXSW_SP_SB_PR(_mode, _size) \ |
b11c3b40 JP |
627 | { \ |
628 | .mode = _mode, \ | |
629 | .size = _size, \ | |
56ade8fe JP |
630 | } |
631 | ||
cce7acca IS |
632 | #define MLXSW_SP_SB_PR_EXT(_mode, _size, _freeze_mode, _freeze_size) \ |
633 | { \ | |
634 | .mode = _mode, \ | |
635 | .size = _size, \ | |
636 | .freeze_mode = _freeze_mode, \ | |
637 | .freeze_size = _freeze_size, \ | |
638 | } | |
639 | ||
265c49b4 | 640 | #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) |
fe099bf6 | 641 | |
857f138f | 642 | /* Order according to mlxsw_sp1_sb_pool_dess */ |
fe099bf6 | 643 | static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { |
bc9f6e94 | 644 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), |
aa99bc70 JP |
645 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), |
646 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), | |
50b5b905 | 647 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), |
bc9f6e94 PM |
648 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, |
649 | true, false), | |
aa99bc70 JP |
650 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), |
651 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), | |
5408f7cb | 652 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), |
cce7acca IS |
653 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI, |
654 | true, true), | |
265c49b4 IS |
655 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, |
656 | MLXSW_SP1_SB_PR_CPU_SIZE, true, false), | |
657 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, | |
658 | MLXSW_SP1_SB_PR_CPU_SIZE, true, false), | |
b11c3b40 JP |
659 | }; |
660 | ||
265c49b4 | 661 | #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) |
fe099bf6 | 662 | |
857f138f | 663 | /* Order according to mlxsw_sp2_sb_pool_dess */ |
fe099bf6 | 664 | static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { |
bc9f6e94 | 665 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), |
fe099bf6 PM |
666 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), |
667 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), | |
50b5b905 | 668 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), |
bc9f6e94 PM |
669 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, |
670 | true, false), | |
fe099bf6 PM |
671 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), |
672 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), | |
673 | MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), | |
cce7acca IS |
674 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI, |
675 | true, true), | |
265c49b4 IS |
676 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, |
677 | MLXSW_SP2_SB_PR_CPU_SIZE, true, false), | |
678 | MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, | |
679 | MLXSW_SP2_SB_PR_CPU_SIZE, true, false), | |
fe099bf6 PM |
680 | }; |
681 | ||
3a4dbfb0 PM |
682 | static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, |
683 | const struct mlxsw_sp_sb_pr *prs, | |
bc9f6e94 | 684 | const struct mlxsw_sp_sb_pool_des *pool_dess, |
3a4dbfb0 | 685 | size_t prs_len) |
56ade8fe | 686 | { |
bc9f6e94 | 687 | /* Round down, unlike mlxsw_sp_bytes_cells(). */ |
d170eb69 | 688 | u32 sb_cells = div_u64(mlxsw_sp->sb->sb_size, mlxsw_sp->sb->cell_size); |
bc9f6e94 | 689 | u32 rest_cells[2] = {sb_cells, sb_cells}; |
56ade8fe JP |
690 | int i; |
691 | int err; | |
692 | ||
bc9f6e94 PM |
693 | /* Calculate how much space to give to the "REST" pools in either |
694 | * direction. | |
695 | */ | |
696 | for (i = 0; i < prs_len; i++) { | |
697 | enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir; | |
698 | u32 size = prs[i].size; | |
699 | u32 size_cells; | |
700 | ||
701 | if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST) | |
702 | continue; | |
703 | ||
704 | size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); | |
705 | if (WARN_ON_ONCE(size_cells > rest_cells[dir])) | |
706 | continue; | |
707 | ||
708 | rest_cells[dir] -= size_cells; | |
709 | } | |
710 | ||
aa99bc70 | 711 | for (i = 0; i < prs_len; i++) { |
f0024f0d PM |
712 | u32 size = prs[i].size; |
713 | u32 size_cells; | |
714 | ||
715 | if (size == MLXSW_SP_SB_INFI) { | |
716 | err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, | |
717 | 0, true); | |
bc9f6e94 PM |
718 | } else if (size == MLXSW_SP_SB_REST) { |
719 | size_cells = rest_cells[pool_dess[i].dir]; | |
720 | err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, | |
721 | size_cells, false); | |
f0024f0d PM |
722 | } else { |
723 | size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); | |
724 | err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, | |
725 | size_cells, false); | |
726 | } | |
56ade8fe JP |
727 | if (err) |
728 | return err; | |
729 | } | |
730 | return 0; | |
731 | } | |
732 | ||
b11c3b40 JP |
733 | #define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \ |
734 | { \ | |
735 | .min_buff = _min_buff, \ | |
736 | .max_buff = _max_buff, \ | |
3a4dbfb0 | 737 | .pool_index = _pool, \ |
56ade8fe JP |
738 | } |
739 | ||
93d3668c IS |
740 | #define MLXSW_SP_SB_CM_ING(_min_buff, _max_buff) \ |
741 | { \ | |
742 | .min_buff = _min_buff, \ | |
743 | .max_buff = _max_buff, \ | |
744 | .pool_index = MLXSW_SP_SB_POOL_ING, \ | |
745 | } | |
746 | ||
747 | #define MLXSW_SP_SB_CM_EGR(_min_buff, _max_buff) \ | |
748 | { \ | |
749 | .min_buff = _min_buff, \ | |
750 | .max_buff = _max_buff, \ | |
751 | .pool_index = MLXSW_SP_SB_POOL_EGR, \ | |
752 | } | |
753 | ||
754 | #define MLXSW_SP_SB_CM_EGR_MC(_min_buff, _max_buff) \ | |
755 | { \ | |
756 | .min_buff = _min_buff, \ | |
757 | .max_buff = _max_buff, \ | |
758 | .pool_index = MLXSW_SP_SB_POOL_EGR_MC, \ | |
f1aaeacd IS |
759 | .freeze_pool = true, \ |
760 | .freeze_thresh = true, \ | |
93d3668c IS |
761 | } |
762 | ||
fe099bf6 | 763 | static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_ingress[] = { |
93d3668c IS |
764 | MLXSW_SP_SB_CM_ING(10000, 8), |
765 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
766 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
767 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
768 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
769 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
770 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
771 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
772 | MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */ | |
50b5b905 | 773 | MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU), |
56ade8fe JP |
774 | }; |
775 | ||
fe099bf6 | 776 | static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_ingress[] = { |
93d3668c IS |
777 | MLXSW_SP_SB_CM_ING(0, 7), |
778 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
779 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
780 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
781 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
782 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
783 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
784 | MLXSW_SP_SB_CM_ING(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
785 | MLXSW_SP_SB_CM_ING(0, 0), /* dummy, this PG does not exist */ | |
50b5b905 | 786 | MLXSW_SP_SB_CM(10000, 8, MLXSW_SP_SB_POOL_ING_CPU), |
fe099bf6 PM |
787 | }; |
788 | ||
789 | static const struct mlxsw_sp_sb_cm mlxsw_sp1_sb_cms_egress[] = { | |
93d3668c IS |
790 | MLXSW_SP_SB_CM_EGR(1500, 9), |
791 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
792 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
793 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
794 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
795 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
796 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
797 | MLXSW_SP_SB_CM_EGR(1500, 9), | |
798 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
799 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
800 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
801 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
802 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
803 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
804 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
805 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
806 | MLXSW_SP_SB_CM_EGR(1, 0xff), | |
b11c3b40 JP |
807 | }; |
808 | ||
fe099bf6 | 809 | static const struct mlxsw_sp_sb_cm mlxsw_sp2_sb_cms_egress[] = { |
93d3668c IS |
810 | MLXSW_SP_SB_CM_EGR(0, 7), |
811 | MLXSW_SP_SB_CM_EGR(0, 7), | |
812 | MLXSW_SP_SB_CM_EGR(0, 7), | |
813 | MLXSW_SP_SB_CM_EGR(0, 7), | |
814 | MLXSW_SP_SB_CM_EGR(0, 7), | |
815 | MLXSW_SP_SB_CM_EGR(0, 7), | |
816 | MLXSW_SP_SB_CM_EGR(0, 7), | |
817 | MLXSW_SP_SB_CM_EGR(0, 7), | |
818 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
819 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
820 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
821 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
822 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
823 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
824 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
825 | MLXSW_SP_SB_CM_EGR_MC(0, MLXSW_SP_SB_INFI), | |
826 | MLXSW_SP_SB_CM_EGR(1, 0xff), | |
fe099bf6 PM |
827 | }; |
828 | ||
7a1ff9f4 | 829 | #define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, MLXSW_SP_SB_POOL_EGR_CPU) |
56ade8fe JP |
830 | |
831 | static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = { | |
e0d84847 | 832 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), |
7a1ff9f4 IS |
833 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), |
834 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), | |
835 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), | |
836 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), | |
837 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), | |
b11c3b40 | 838 | MLXSW_SP_CPU_PORT_SB_CM, |
7a1ff9f4 | 839 | MLXSW_SP_SB_CM(1000, 8, MLXSW_SP_SB_POOL_EGR_CPU), |
b11c3b40 JP |
840 | MLXSW_SP_CPU_PORT_SB_CM, |
841 | MLXSW_SP_CPU_PORT_SB_CM, | |
842 | MLXSW_SP_CPU_PORT_SB_CM, | |
843 | MLXSW_SP_CPU_PORT_SB_CM, | |
844 | MLXSW_SP_CPU_PORT_SB_CM, | |
845 | MLXSW_SP_CPU_PORT_SB_CM, | |
846 | MLXSW_SP_CPU_PORT_SB_CM, | |
847 | MLXSW_SP_CPU_PORT_SB_CM, | |
848 | MLXSW_SP_CPU_PORT_SB_CM, | |
849 | MLXSW_SP_CPU_PORT_SB_CM, | |
850 | MLXSW_SP_CPU_PORT_SB_CM, | |
851 | MLXSW_SP_CPU_PORT_SB_CM, | |
852 | MLXSW_SP_CPU_PORT_SB_CM, | |
853 | MLXSW_SP_CPU_PORT_SB_CM, | |
854 | MLXSW_SP_CPU_PORT_SB_CM, | |
855 | MLXSW_SP_CPU_PORT_SB_CM, | |
856 | MLXSW_SP_CPU_PORT_SB_CM, | |
857 | MLXSW_SP_CPU_PORT_SB_CM, | |
858 | MLXSW_SP_CPU_PORT_SB_CM, | |
859 | MLXSW_SP_CPU_PORT_SB_CM, | |
860 | MLXSW_SP_CPU_PORT_SB_CM, | |
861 | MLXSW_SP_CPU_PORT_SB_CM, | |
862 | MLXSW_SP_CPU_PORT_SB_CM, | |
863 | MLXSW_SP_CPU_PORT_SB_CM, | |
56ade8fe JP |
864 | }; |
865 | ||
5be3637e PM |
866 | static bool |
867 | mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index) | |
868 | { | |
869 | struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); | |
870 | ||
871 | return pr->mode == MLXSW_REG_SBPR_MODE_STATIC; | |
872 | } | |
873 | ||
b11c3b40 JP |
874 | static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, |
875 | enum mlxsw_reg_sbxx_dir dir, | |
876 | const struct mlxsw_sp_sb_cm *cms, | |
877 | size_t cms_len) | |
56ade8fe | 878 | { |
5d65f5f4 | 879 | const struct mlxsw_sp_sb_vals *sb_vals = mlxsw_sp->sb_vals; |
56ade8fe JP |
880 | int i; |
881 | int err; | |
882 | ||
883 | for (i = 0; i < cms_len; i++) { | |
884 | const struct mlxsw_sp_sb_cm *cm; | |
18281f2d | 885 | u32 min_buff; |
5be3637e | 886 | u32 max_buff; |
56ade8fe | 887 | |
b11c3b40 JP |
888 | if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS) |
889 | continue; /* PG number 8 does not exist, skip it */ | |
56ade8fe | 890 | cm = &cms[i]; |
5d65f5f4 | 891 | if (WARN_ON(sb_vals->pool_dess[cm->pool_index].dir != dir)) |
3a4dbfb0 PM |
892 | continue; |
893 | ||
18281f2d | 894 | min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff); |
5be3637e PM |
895 | max_buff = cm->max_buff; |
896 | if (max_buff == MLXSW_SP_SB_INFI) { | |
d144e3a2 PM |
897 | err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, |
898 | min_buff, 0, | |
899 | true, cm->pool_index); | |
5be3637e PM |
900 | } else { |
901 | if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, | |
902 | cm->pool_index)) | |
903 | max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, | |
904 | max_buff); | |
d144e3a2 | 905 | err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, |
5be3637e | 906 | min_buff, max_buff, |
d144e3a2 | 907 | false, cm->pool_index); |
5be3637e | 908 | } |
56ade8fe JP |
909 | if (err) |
910 | return err; | |
911 | } | |
912 | return 0; | |
913 | } | |
914 | ||
915 | static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port) | |
916 | { | |
bb60a62e | 917 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
b11c3b40 JP |
918 | int err; |
919 | ||
bb60a62e | 920 | err = __mlxsw_sp_sb_cms_init(mlxsw_sp, |
b11c3b40 JP |
921 | mlxsw_sp_port->local_port, |
922 | MLXSW_REG_SBXX_DIR_INGRESS, | |
bb60a62e PM |
923 | mlxsw_sp->sb_vals->cms_ingress, |
924 | mlxsw_sp->sb_vals->cms_ingress_count); | |
b11c3b40 JP |
925 | if (err) |
926 | return err; | |
927 | return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp, | |
928 | mlxsw_sp_port->local_port, | |
929 | MLXSW_REG_SBXX_DIR_EGRESS, | |
bb60a62e PM |
930 | mlxsw_sp->sb_vals->cms_egress, |
931 | mlxsw_sp->sb_vals->cms_egress_count); | |
56ade8fe JP |
932 | } |
933 | ||
934 | static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp) | |
935 | { | |
b11c3b40 | 936 | return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS, |
bb60a62e PM |
937 | mlxsw_sp->sb_vals->cms_cpu, |
938 | mlxsw_sp->sb_vals->cms_cpu_count); | |
56ade8fe JP |
939 | } |
940 | ||
b11c3b40 JP |
941 | #define MLXSW_SP_SB_PM(_min_buff, _max_buff) \ |
942 | { \ | |
943 | .min_buff = _min_buff, \ | |
944 | .max_buff = _max_buff, \ | |
56ade8fe JP |
945 | } |
946 | ||
857f138f | 947 | /* Order according to mlxsw_sp1_sb_pool_dess */ |
fe099bf6 | 948 | static const struct mlxsw_sp_sb_pm mlxsw_sp1_sb_pms[] = { |
c30a53c7 JP |
949 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), |
950 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
951 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
50b5b905 | 952 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), |
b11c3b40 | 953 | MLXSW_SP_SB_PM(0, 7), |
c30a53c7 JP |
954 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), |
955 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
956 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
e83c045e | 957 | MLXSW_SP_SB_PM(10000, 90000), |
265c49b4 IS |
958 | MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */ |
959 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
b11c3b40 JP |
960 | }; |
961 | ||
857f138f | 962 | /* Order according to mlxsw_sp2_sb_pool_dess */ |
fe099bf6 | 963 | static const struct mlxsw_sp_sb_pm mlxsw_sp2_sb_pms[] = { |
fe099bf6 PM |
964 | MLXSW_SP_SB_PM(0, 7), |
965 | MLXSW_SP_SB_PM(0, 0), | |
966 | MLXSW_SP_SB_PM(0, 0), | |
50b5b905 | 967 | MLXSW_SP_SB_PM(0, 0), |
fe099bf6 PM |
968 | MLXSW_SP_SB_PM(0, 7), |
969 | MLXSW_SP_SB_PM(0, 0), | |
970 | MLXSW_SP_SB_PM(0, 0), | |
971 | MLXSW_SP_SB_PM(0, 0), | |
d5949d92 | 972 | MLXSW_SP_SB_PM(10000, 90000), |
265c49b4 IS |
973 | MLXSW_SP_SB_PM(0, 8), /* 50% occupancy */ |
974 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN), | |
fe099bf6 PM |
975 | }; |
976 | ||
7a1ff9f4 IS |
977 | /* Order according to mlxsw_sp*_sb_pool_dess */ |
978 | static const struct mlxsw_sp_sb_pm mlxsw_sp_cpu_port_sb_pms[] = { | |
979 | MLXSW_SP_SB_PM(0, 0), | |
980 | MLXSW_SP_SB_PM(0, 0), | |
981 | MLXSW_SP_SB_PM(0, 0), | |
982 | MLXSW_SP_SB_PM(0, 0), | |
983 | MLXSW_SP_SB_PM(0, 0), | |
984 | MLXSW_SP_SB_PM(0, 0), | |
985 | MLXSW_SP_SB_PM(0, 0), | |
986 | MLXSW_SP_SB_PM(0, 0), | |
987 | MLXSW_SP_SB_PM(0, 90000), | |
988 | MLXSW_SP_SB_PM(0, 0), | |
989 | MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX), | |
990 | }; | |
991 | ||
24a7cc1e | 992 | static int mlxsw_sp_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port, |
6d28725c IS |
993 | const struct mlxsw_sp_sb_pm *pms, |
994 | bool skip_ingress) | |
56ade8fe | 995 | { |
24a7cc1e | 996 | int i, err; |
56ade8fe | 997 | |
cc1ce6ff | 998 | for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { |
24a7cc1e | 999 | const struct mlxsw_sp_sb_pm *pm = &pms[i]; |
6d28725c | 1000 | const struct mlxsw_sp_sb_pool_des *des; |
5be3637e | 1001 | u32 max_buff; |
41057e28 | 1002 | u32 min_buff; |
56ade8fe | 1003 | |
6d28725c IS |
1004 | des = &mlxsw_sp->sb_vals->pool_dess[i]; |
1005 | if (skip_ingress && des->dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
1006 | continue; | |
1007 | ||
41057e28 | 1008 | min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff); |
5be3637e PM |
1009 | max_buff = pm->max_buff; |
1010 | if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, i)) | |
1011 | max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, max_buff); | |
24a7cc1e IS |
1012 | err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, min_buff, |
1013 | max_buff); | |
56ade8fe JP |
1014 | if (err) |
1015 | return err; | |
1016 | } | |
1017 | return 0; | |
1018 | } | |
1019 | ||
24a7cc1e IS |
1020 | static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port) |
1021 | { | |
1022 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1023 | ||
1024 | return mlxsw_sp_sb_pms_init(mlxsw_sp, mlxsw_sp_port->local_port, | |
6d28725c | 1025 | mlxsw_sp->sb_vals->pms, false); |
24a7cc1e IS |
1026 | } |
1027 | ||
7a1ff9f4 IS |
1028 | static int mlxsw_sp_cpu_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp) |
1029 | { | |
1030 | return mlxsw_sp_sb_pms_init(mlxsw_sp, 0, mlxsw_sp->sb_vals->pms_cpu, | |
1031 | true); | |
1032 | } | |
1033 | ||
93d3668c | 1034 | #define MLXSW_SP_SB_MM(_min_buff, _max_buff) \ |
b11c3b40 JP |
1035 | { \ |
1036 | .min_buff = _min_buff, \ | |
1037 | .max_buff = _max_buff, \ | |
93d3668c | 1038 | .pool_index = MLXSW_SP_SB_POOL_EGR, \ |
56ade8fe JP |
1039 | } |
1040 | ||
1041 | static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = { | |
93d3668c IS |
1042 | MLXSW_SP_SB_MM(0, 6), |
1043 | MLXSW_SP_SB_MM(0, 6), | |
1044 | MLXSW_SP_SB_MM(0, 6), | |
1045 | MLXSW_SP_SB_MM(0, 6), | |
1046 | MLXSW_SP_SB_MM(0, 6), | |
1047 | MLXSW_SP_SB_MM(0, 6), | |
1048 | MLXSW_SP_SB_MM(0, 6), | |
1049 | MLXSW_SP_SB_MM(0, 6), | |
1050 | MLXSW_SP_SB_MM(0, 6), | |
1051 | MLXSW_SP_SB_MM(0, 6), | |
1052 | MLXSW_SP_SB_MM(0, 6), | |
1053 | MLXSW_SP_SB_MM(0, 6), | |
1054 | MLXSW_SP_SB_MM(0, 6), | |
1055 | MLXSW_SP_SB_MM(0, 6), | |
1056 | MLXSW_SP_SB_MM(0, 6), | |
56ade8fe JP |
1057 | }; |
1058 | ||
56ade8fe JP |
1059 | static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp) |
1060 | { | |
1061 | char sbmm_pl[MLXSW_REG_SBMM_LEN]; | |
1062 | int i; | |
1063 | int err; | |
1064 | ||
13f35cc4 | 1065 | for (i = 0; i < mlxsw_sp->sb_vals->mms_count; i++) { |
3a4dbfb0 | 1066 | const struct mlxsw_sp_sb_pool_des *des; |
56ade8fe | 1067 | const struct mlxsw_sp_sb_mm *mc; |
18281f2d | 1068 | u32 min_buff; |
56ade8fe | 1069 | |
13f35cc4 | 1070 | mc = &mlxsw_sp->sb_vals->mms[i]; |
5d65f5f4 | 1071 | des = &mlxsw_sp->sb_vals->pool_dess[mc->pool_index]; |
5be3637e PM |
1072 | /* All pools used by sb_mm's are initialized using dynamic |
1073 | * thresholds, therefore 'max_buff' isn't specified in cells. | |
18281f2d IS |
1074 | */ |
1075 | min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff); | |
1076 | mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff, | |
3a4dbfb0 | 1077 | des->pool); |
56ade8fe JP |
1078 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl); |
1079 | if (err) | |
1080 | return err; | |
1081 | } | |
1082 | return 0; | |
1083 | } | |
1084 | ||
5d65f5f4 PM |
1085 | static void mlxsw_sp_pool_count(struct mlxsw_sp *mlxsw_sp, |
1086 | u16 *p_ingress_len, u16 *p_egress_len) | |
3a4dbfb0 PM |
1087 | { |
1088 | int i; | |
1089 | ||
857f138f | 1090 | for (i = 0; i < mlxsw_sp->sb_vals->pool_count; ++i) { |
5d65f5f4 | 1091 | if (mlxsw_sp->sb_vals->pool_dess[i].dir == |
857f138f IS |
1092 | MLXSW_REG_SBXX_DIR_INGRESS) |
1093 | (*p_ingress_len)++; | |
1094 | else | |
1095 | (*p_egress_len)++; | |
1096 | } | |
3a4dbfb0 | 1097 | |
857f138f | 1098 | WARN(*p_egress_len == 0, "No egress pools\n"); |
3a4dbfb0 PM |
1099 | } |
1100 | ||
c39f3e0e | 1101 | const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals = { |
fe099bf6 PM |
1102 | .pool_count = ARRAY_SIZE(mlxsw_sp1_sb_pool_dess), |
1103 | .pool_dess = mlxsw_sp1_sb_pool_dess, | |
1104 | .pms = mlxsw_sp1_sb_pms, | |
7a1ff9f4 | 1105 | .pms_cpu = mlxsw_sp_cpu_port_sb_pms, |
fe099bf6 | 1106 | .prs = mlxsw_sp1_sb_prs, |
13f35cc4 | 1107 | .mms = mlxsw_sp_sb_mms, |
fe099bf6 PM |
1108 | .cms_ingress = mlxsw_sp1_sb_cms_ingress, |
1109 | .cms_egress = mlxsw_sp1_sb_cms_egress, | |
bb60a62e | 1110 | .cms_cpu = mlxsw_sp_cpu_port_sb_cms, |
13f35cc4 | 1111 | .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms), |
fe099bf6 PM |
1112 | .cms_ingress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_ingress), |
1113 | .cms_egress_count = ARRAY_SIZE(mlxsw_sp1_sb_cms_egress), | |
bb60a62e | 1114 | .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms), |
c39f3e0e PM |
1115 | }; |
1116 | ||
1117 | const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals = { | |
fe099bf6 PM |
1118 | .pool_count = ARRAY_SIZE(mlxsw_sp2_sb_pool_dess), |
1119 | .pool_dess = mlxsw_sp2_sb_pool_dess, | |
1120 | .pms = mlxsw_sp2_sb_pms, | |
7a1ff9f4 | 1121 | .pms_cpu = mlxsw_sp_cpu_port_sb_pms, |
fe099bf6 | 1122 | .prs = mlxsw_sp2_sb_prs, |
13f35cc4 | 1123 | .mms = mlxsw_sp_sb_mms, |
fe099bf6 PM |
1124 | .cms_ingress = mlxsw_sp2_sb_cms_ingress, |
1125 | .cms_egress = mlxsw_sp2_sb_cms_egress, | |
bb60a62e | 1126 | .cms_cpu = mlxsw_sp_cpu_port_sb_cms, |
13f35cc4 | 1127 | .mms_count = ARRAY_SIZE(mlxsw_sp_sb_mms), |
fe099bf6 PM |
1128 | .cms_ingress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_ingress), |
1129 | .cms_egress_count = ARRAY_SIZE(mlxsw_sp2_sb_cms_egress), | |
bb60a62e | 1130 | .cms_cpu_count = ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms), |
c39f3e0e PM |
1131 | }; |
1132 | ||
56ade8fe JP |
1133 | int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) |
1134 | { | |
bb6c346c | 1135 | u32 max_headroom_size; |
857f138f IS |
1136 | u16 ing_pool_count = 0; |
1137 | u16 eg_pool_count = 0; | |
56ade8fe JP |
1138 | int err; |
1139 | ||
18281f2d IS |
1140 | if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) |
1141 | return -EIO; | |
18281f2d | 1142 | |
914c4fc1 | 1143 | if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER)) |
d3daae1b | 1144 | return -EIO; |
d3daae1b | 1145 | |
bb6c346c PM |
1146 | if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE)) |
1147 | return -EIO; | |
1148 | ||
33cbd87c IS |
1149 | mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); |
1150 | if (!mlxsw_sp->sb) | |
1151 | return -ENOMEM; | |
1152 | mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); | |
fe07d723 | 1153 | mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, |
914c4fc1 | 1154 | GUARANTEED_SHARED_BUFFER); |
bb6c346c PM |
1155 | max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, |
1156 | MAX_HEADROOM_SIZE); | |
1157 | /* Round down, because this limit must not be overstepped. */ | |
1158 | mlxsw_sp->sb->max_headroom_cells = max_headroom_size / | |
1159 | mlxsw_sp->sb->cell_size; | |
1160 | ||
5ec2ee7d | 1161 | err = mlxsw_sp_sb_ports_init(mlxsw_sp); |
56ade8fe | 1162 | if (err) |
33cbd87c | 1163 | goto err_sb_ports_init; |
5d25232e | 1164 | err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs, |
bc9f6e94 | 1165 | mlxsw_sp->sb_vals->pool_dess, |
5d25232e | 1166 | mlxsw_sp->sb_vals->pool_count); |
5ec2ee7d IS |
1167 | if (err) |
1168 | goto err_sb_prs_init; | |
56ade8fe JP |
1169 | err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp); |
1170 | if (err) | |
5ec2ee7d | 1171 | goto err_sb_cpu_port_sb_cms_init; |
7a1ff9f4 IS |
1172 | err = mlxsw_sp_cpu_port_sb_pms_init(mlxsw_sp); |
1173 | if (err) | |
1174 | goto err_sb_cpu_port_pms_init; | |
56ade8fe | 1175 | err = mlxsw_sp_sb_mms_init(mlxsw_sp); |
0f433fa0 | 1176 | if (err) |
5ec2ee7d | 1177 | goto err_sb_mms_init; |
5d65f5f4 | 1178 | mlxsw_sp_pool_count(mlxsw_sp, &ing_pool_count, &eg_pool_count); |
fe07d723 PM |
1179 | err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, |
1180 | mlxsw_sp->sb->sb_size, | |
3a4dbfb0 PM |
1181 | ing_pool_count, |
1182 | eg_pool_count, | |
5f95d20b PM |
1183 | MLXSW_SP_SB_ING_TC_COUNT, |
1184 | MLXSW_SP_SB_EG_TC_COUNT); | |
5ec2ee7d IS |
1185 | if (err) |
1186 | goto err_devlink_sb_register; | |
1187 | ||
1188 | return 0; | |
1189 | ||
1190 | err_devlink_sb_register: | |
1191 | err_sb_mms_init: | |
7a1ff9f4 | 1192 | err_sb_cpu_port_pms_init: |
5ec2ee7d IS |
1193 | err_sb_cpu_port_sb_cms_init: |
1194 | err_sb_prs_init: | |
1195 | mlxsw_sp_sb_ports_fini(mlxsw_sp); | |
33cbd87c IS |
1196 | err_sb_ports_init: |
1197 | kfree(mlxsw_sp->sb); | |
5ec2ee7d | 1198 | return err; |
0f433fa0 | 1199 | } |
56ade8fe | 1200 | |
0f433fa0 JP |
1201 | void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp) |
1202 | { | |
1203 | devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0); | |
5ec2ee7d | 1204 | mlxsw_sp_sb_ports_fini(mlxsw_sp); |
33cbd87c | 1205 | kfree(mlxsw_sp->sb); |
56ade8fe JP |
1206 | } |
1207 | ||
1208 | int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) | |
1209 | { | |
1210 | int err; | |
1211 | ||
3a77f5a2 PM |
1212 | mlxsw_sp_port->hdroom = kzalloc(sizeof(*mlxsw_sp_port->hdroom), GFP_KERNEL); |
1213 | if (!mlxsw_sp_port->hdroom) | |
1214 | return -ENOMEM; | |
0103a3e4 | 1215 | mlxsw_sp_port->hdroom->mtu = mlxsw_sp_port->dev->mtu; |
3a77f5a2 | 1216 | |
dd6cb0f9 | 1217 | err = mlxsw_sp_port_headroom_init(mlxsw_sp_port); |
56ade8fe | 1218 | if (err) |
3a77f5a2 | 1219 | goto err_headroom_init; |
56ade8fe JP |
1220 | err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port); |
1221 | if (err) | |
3a77f5a2 | 1222 | goto err_port_sb_cms_init; |
56ade8fe | 1223 | err = mlxsw_sp_port_sb_pms_init(mlxsw_sp_port); |
3a77f5a2 PM |
1224 | if (err) |
1225 | goto err_port_sb_pms_init; | |
1226 | return 0; | |
56ade8fe | 1227 | |
3a77f5a2 PM |
1228 | err_port_sb_pms_init: |
1229 | err_port_sb_cms_init: | |
1230 | err_headroom_init: | |
1231 | kfree(mlxsw_sp_port->hdroom); | |
56ade8fe JP |
1232 | return err; |
1233 | } | |
0f433fa0 | 1234 | |
3a77f5a2 PM |
1235 | void mlxsw_sp_port_buffers_fini(struct mlxsw_sp_port *mlxsw_sp_port) |
1236 | { | |
1237 | kfree(mlxsw_sp_port->hdroom); | |
1238 | } | |
1239 | ||
0f433fa0 JP |
1240 | int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core, |
1241 | unsigned int sb_index, u16 pool_index, | |
1242 | struct devlink_sb_pool_info *pool_info) | |
1243 | { | |
1244 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | |
5d65f5f4 | 1245 | enum mlxsw_reg_sbxx_dir dir; |
3a4dbfb0 | 1246 | struct mlxsw_sp_sb_pr *pr; |
0f433fa0 | 1247 | |
5d65f5f4 | 1248 | dir = mlxsw_sp->sb_vals->pool_dess[pool_index].dir; |
3a4dbfb0 | 1249 | pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); |
1a9234e6 | 1250 | pool_info->pool_type = (enum devlink_sb_pool_type) dir; |
18281f2d | 1251 | pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size); |
1a9234e6 | 1252 | pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode; |
bff5731d | 1253 | pool_info->cell_size = mlxsw_sp->sb->cell_size; |
0f433fa0 JP |
1254 | return 0; |
1255 | } | |
1256 | ||
1257 | int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, | |
1258 | unsigned int sb_index, u16 pool_index, u32 size, | |
8f686206 IS |
1259 | enum devlink_sb_threshold_type threshold_type, |
1260 | struct netlink_ext_ack *extack) | |
0f433fa0 JP |
1261 | { |
1262 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | |
18281f2d | 1263 | u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size); |
0636f4de | 1264 | const struct mlxsw_sp_sb_pr *pr; |
1a9234e6 | 1265 | enum mlxsw_reg_sbpr_mode mode; |
0f433fa0 | 1266 | |
0636f4de IS |
1267 | mode = (enum mlxsw_reg_sbpr_mode) threshold_type; |
1268 | pr = &mlxsw_sp->sb_vals->prs[pool_index]; | |
1269 | ||
914c4fc1 PM |
1270 | if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, |
1271 | GUARANTEED_SHARED_BUFFER)) { | |
8f686206 | 1272 | NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size"); |
87259f18 | 1273 | return -EINVAL; |
8f686206 | 1274 | } |
87259f18 | 1275 | |
0636f4de IS |
1276 | if (pr->freeze_mode && pr->mode != mode) { |
1277 | NL_SET_ERR_MSG_MOD(extack, "Changing this pool's threshold type is forbidden"); | |
1278 | return -EINVAL; | |
acf5133b | 1279 | } |
0636f4de IS |
1280 | |
1281 | if (pr->freeze_size && pr->size != size) { | |
1282 | NL_SET_ERR_MSG_MOD(extack, "Changing this pool's size is forbidden"); | |
1283 | return -EINVAL; | |
acf5133b | 1284 | } |
0636f4de | 1285 | |
f0024f0d PM |
1286 | return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, |
1287 | pool_size, false); | |
0f433fa0 JP |
1288 | } |
1289 | ||
1290 | #define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */ | |
1291 | ||
3a4dbfb0 PM |
1292 | static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u16 pool_index, |
1293 | u32 max_buff) | |
0f433fa0 | 1294 | { |
3a4dbfb0 | 1295 | struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); |
0f433fa0 JP |
1296 | |
1297 | if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) | |
1298 | return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; | |
18281f2d | 1299 | return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff); |
0f433fa0 JP |
1300 | } |
1301 | ||
3a4dbfb0 | 1302 | static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u16 pool_index, |
8f686206 IS |
1303 | u32 threshold, u32 *p_max_buff, |
1304 | struct netlink_ext_ack *extack) | |
0f433fa0 | 1305 | { |
3a4dbfb0 | 1306 | struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index); |
0f433fa0 JP |
1307 | |
1308 | if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) { | |
1309 | int val; | |
1310 | ||
1311 | val = threshold + MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET; | |
1312 | if (val < MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN || | |
8f686206 IS |
1313 | val > MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX) { |
1314 | NL_SET_ERR_MSG_MOD(extack, "Invalid dynamic threshold value"); | |
0f433fa0 | 1315 | return -EINVAL; |
8f686206 | 1316 | } |
0f433fa0 JP |
1317 | *p_max_buff = val; |
1318 | } else { | |
18281f2d | 1319 | *p_max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, threshold); |
0f433fa0 JP |
1320 | } |
1321 | return 0; | |
1322 | } | |
1323 | ||
1324 | int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, | |
1325 | unsigned int sb_index, u16 pool_index, | |
1326 | u32 *p_threshold) | |
1327 | { | |
1328 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1329 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1330 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1331 | u8 local_port = mlxsw_sp_port->local_port; | |
0f433fa0 | 1332 | struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, |
3a4dbfb0 | 1333 | pool_index); |
0f433fa0 | 1334 | |
3a4dbfb0 | 1335 | *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool_index, |
0f433fa0 JP |
1336 | pm->max_buff); |
1337 | return 0; | |
1338 | } | |
1339 | ||
1340 | int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port, | |
1341 | unsigned int sb_index, u16 pool_index, | |
8f686206 | 1342 | u32 threshold, struct netlink_ext_ack *extack) |
0f433fa0 JP |
1343 | { |
1344 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1345 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1346 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1347 | u8 local_port = mlxsw_sp_port->local_port; | |
0f433fa0 JP |
1348 | u32 max_buff; |
1349 | int err; | |
1350 | ||
9d0aa053 ST |
1351 | if (local_port == MLXSW_PORT_CPU_PORT) { |
1352 | NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's threshold is forbidden"); | |
1353 | return -EINVAL; | |
1354 | } | |
1355 | ||
3a4dbfb0 | 1356 | err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, |
8f686206 | 1357 | threshold, &max_buff, extack); |
0f433fa0 JP |
1358 | if (err) |
1359 | return err; | |
1360 | ||
3a4dbfb0 | 1361 | return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool_index, |
0f433fa0 JP |
1362 | 0, max_buff); |
1363 | } | |
1364 | ||
1365 | int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port, | |
1366 | unsigned int sb_index, u16 tc_index, | |
1367 | enum devlink_sb_pool_type pool_type, | |
1368 | u16 *p_pool_index, u32 *p_threshold) | |
1369 | { | |
1370 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1371 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1372 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1373 | u8 local_port = mlxsw_sp_port->local_port; | |
1374 | u8 pg_buff = tc_index; | |
1a9234e6 | 1375 | enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; |
0f433fa0 JP |
1376 | struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, |
1377 | pg_buff, dir); | |
1378 | ||
3a4dbfb0 | 1379 | *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool_index, |
0f433fa0 | 1380 | cm->max_buff); |
3a4dbfb0 | 1381 | *p_pool_index = cm->pool_index; |
0f433fa0 JP |
1382 | return 0; |
1383 | } | |
1384 | ||
1385 | int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port, | |
1386 | unsigned int sb_index, u16 tc_index, | |
1387 | enum devlink_sb_pool_type pool_type, | |
8f686206 IS |
1388 | u16 pool_index, u32 threshold, |
1389 | struct netlink_ext_ack *extack) | |
0f433fa0 JP |
1390 | { |
1391 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1392 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1393 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1394 | u8 local_port = mlxsw_sp_port->local_port; | |
f7936d0b | 1395 | const struct mlxsw_sp_sb_cm *cm; |
0f433fa0 | 1396 | u8 pg_buff = tc_index; |
1a9234e6 | 1397 | enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; |
0f433fa0 JP |
1398 | u32 max_buff; |
1399 | int err; | |
1400 | ||
9d0aa053 ST |
1401 | if (local_port == MLXSW_PORT_CPU_PORT) { |
1402 | NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's binding is forbidden"); | |
1403 | return -EINVAL; | |
1404 | } | |
1405 | ||
8f686206 IS |
1406 | if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir) { |
1407 | NL_SET_ERR_MSG_MOD(extack, "Binding egress TC to ingress pool and vice versa is forbidden"); | |
8912862f | 1408 | return -EINVAL; |
f7936d0b IS |
1409 | } |
1410 | ||
1411 | if (dir == MLXSW_REG_SBXX_DIR_INGRESS) | |
1412 | cm = &mlxsw_sp->sb_vals->cms_ingress[tc_index]; | |
1413 | else | |
1414 | cm = &mlxsw_sp->sb_vals->cms_egress[tc_index]; | |
1415 | ||
1416 | if (cm->freeze_pool && cm->pool_index != pool_index) { | |
1417 | NL_SET_ERR_MSG_MOD(extack, "Binding this TC to a different pool is forbidden"); | |
1418 | return -EINVAL; | |
1419 | } | |
1420 | ||
1421 | if (cm->freeze_thresh && cm->max_buff != threshold) { | |
1422 | NL_SET_ERR_MSG_MOD(extack, "Changing this TC's threshold is forbidden"); | |
1423 | return -EINVAL; | |
8f686206 | 1424 | } |
8912862f | 1425 | |
3a4dbfb0 | 1426 | err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index, |
8f686206 | 1427 | threshold, &max_buff, extack); |
0f433fa0 JP |
1428 | if (err) |
1429 | return err; | |
1430 | ||
3a4dbfb0 | 1431 | return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, |
d144e3a2 | 1432 | 0, max_buff, false, pool_index); |
0f433fa0 | 1433 | } |
2d0ed39f JP |
1434 | |
1435 | #define MASKED_COUNT_MAX \ | |
5f95d20b PM |
1436 | (MLXSW_REG_SBSR_REC_MAX_COUNT / \ |
1437 | (MLXSW_SP_SB_ING_TC_COUNT + MLXSW_SP_SB_EG_TC_COUNT)) | |
2d0ed39f JP |
1438 | |
1439 | struct mlxsw_sp_sb_sr_occ_query_cb_ctx { | |
1440 | u8 masked_count; | |
1441 | u8 local_port_1; | |
1442 | }; | |
1443 | ||
1444 | static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core, | |
1445 | char *sbsr_pl, size_t sbsr_pl_len, | |
1446 | unsigned long cb_priv) | |
1447 | { | |
1448 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | |
1449 | struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; | |
1450 | u8 masked_count; | |
1451 | u8 local_port; | |
1452 | int rec_index = 0; | |
1453 | struct mlxsw_sp_sb_cm *cm; | |
1454 | int i; | |
1455 | ||
1456 | memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx)); | |
1457 | ||
1458 | masked_count = 0; | |
1459 | for (local_port = cb_ctx.local_port_1; | |
5ec2ee7d | 1460 | local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { |
2d0ed39f JP |
1461 | if (!mlxsw_sp->ports[local_port]) |
1462 | continue; | |
a759ab6d ST |
1463 | if (local_port == MLXSW_PORT_CPU_PORT) { |
1464 | /* Ingress quotas are not supported for the CPU port */ | |
1465 | masked_count++; | |
1466 | continue; | |
1467 | } | |
5f95d20b | 1468 | for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) { |
2d0ed39f JP |
1469 | cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, |
1470 | MLXSW_REG_SBXX_DIR_INGRESS); | |
1471 | mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, | |
1472 | &cm->occ.cur, &cm->occ.max); | |
1473 | } | |
1474 | if (++masked_count == cb_ctx.masked_count) | |
1475 | break; | |
1476 | } | |
1477 | masked_count = 0; | |
1478 | for (local_port = cb_ctx.local_port_1; | |
5ec2ee7d | 1479 | local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { |
2d0ed39f JP |
1480 | if (!mlxsw_sp->ports[local_port]) |
1481 | continue; | |
5f95d20b | 1482 | for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) { |
2d0ed39f JP |
1483 | cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i, |
1484 | MLXSW_REG_SBXX_DIR_EGRESS); | |
1485 | mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++, | |
1486 | &cm->occ.cur, &cm->occ.max); | |
1487 | } | |
1488 | if (++masked_count == cb_ctx.masked_count) | |
1489 | break; | |
1490 | } | |
1491 | } | |
1492 | ||
1493 | int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core, | |
1494 | unsigned int sb_index) | |
1495 | { | |
1496 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | |
1497 | struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx; | |
1498 | unsigned long cb_priv; | |
1499 | LIST_HEAD(bulk_list); | |
1500 | char *sbsr_pl; | |
1501 | u8 masked_count; | |
1502 | u8 local_port_1; | |
a759ab6d | 1503 | u8 local_port; |
2d0ed39f JP |
1504 | int i; |
1505 | int err; | |
1506 | int err2; | |
1507 | ||
1508 | sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); | |
1509 | if (!sbsr_pl) | |
1510 | return -ENOMEM; | |
1511 | ||
a759ab6d | 1512 | local_port = MLXSW_PORT_CPU_PORT; |
2d0ed39f | 1513 | next_batch: |
2d0ed39f JP |
1514 | local_port_1 = local_port; |
1515 | masked_count = 0; | |
1516 | mlxsw_reg_sbsr_pack(sbsr_pl, false); | |
5f95d20b | 1517 | for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) |
2d0ed39f | 1518 | mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); |
5f95d20b | 1519 | for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) |
2d0ed39f | 1520 | mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); |
5ec2ee7d | 1521 | for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { |
2d0ed39f JP |
1522 | if (!mlxsw_sp->ports[local_port]) |
1523 | continue; | |
a759ab6d ST |
1524 | if (local_port != MLXSW_PORT_CPU_PORT) { |
1525 | /* Ingress quotas are not supported for the CPU port */ | |
1526 | mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, | |
1527 | local_port, 1); | |
1528 | } | |
2d0ed39f | 1529 | mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); |
5d65f5f4 | 1530 | for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { |
2d0ed39f | 1531 | err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i, |
2d0ed39f JP |
1532 | &bulk_list); |
1533 | if (err) | |
1534 | goto out; | |
1535 | } | |
1536 | if (++masked_count == MASKED_COUNT_MAX) | |
1537 | goto do_query; | |
1538 | } | |
1539 | ||
1540 | do_query: | |
1541 | cb_ctx.masked_count = masked_count; | |
1542 | cb_ctx.local_port_1 = local_port_1; | |
1543 | memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx)); | |
1544 | err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, | |
1545 | &bulk_list, mlxsw_sp_sb_sr_occ_query_cb, | |
1546 | cb_priv); | |
1547 | if (err) | |
1548 | goto out; | |
a759ab6d ST |
1549 | if (local_port < mlxsw_core_max_ports(mlxsw_core)) { |
1550 | local_port++; | |
2d0ed39f | 1551 | goto next_batch; |
a759ab6d | 1552 | } |
2d0ed39f JP |
1553 | |
1554 | out: | |
1555 | err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); | |
1556 | if (!err) | |
1557 | err = err2; | |
1558 | kfree(sbsr_pl); | |
1559 | return err; | |
1560 | } | |
1561 | ||
1562 | int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core, | |
1563 | unsigned int sb_index) | |
1564 | { | |
1565 | struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); | |
1566 | LIST_HEAD(bulk_list); | |
1567 | char *sbsr_pl; | |
1568 | unsigned int masked_count; | |
a759ab6d | 1569 | u8 local_port; |
2d0ed39f JP |
1570 | int i; |
1571 | int err; | |
1572 | int err2; | |
1573 | ||
1574 | sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL); | |
1575 | if (!sbsr_pl) | |
1576 | return -ENOMEM; | |
1577 | ||
a759ab6d | 1578 | local_port = MLXSW_PORT_CPU_PORT; |
2d0ed39f | 1579 | next_batch: |
2d0ed39f JP |
1580 | masked_count = 0; |
1581 | mlxsw_reg_sbsr_pack(sbsr_pl, true); | |
5f95d20b | 1582 | for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) |
2d0ed39f | 1583 | mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1); |
5f95d20b | 1584 | for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) |
2d0ed39f | 1585 | mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1); |
5ec2ee7d | 1586 | for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) { |
2d0ed39f JP |
1587 | if (!mlxsw_sp->ports[local_port]) |
1588 | continue; | |
a759ab6d ST |
1589 | if (local_port != MLXSW_PORT_CPU_PORT) { |
1590 | /* Ingress quotas are not supported for the CPU port */ | |
1591 | mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, | |
1592 | local_port, 1); | |
1593 | } | |
2d0ed39f | 1594 | mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1); |
5d65f5f4 | 1595 | for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) { |
2d0ed39f | 1596 | err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i, |
2d0ed39f JP |
1597 | &bulk_list); |
1598 | if (err) | |
1599 | goto out; | |
1600 | } | |
1601 | if (++masked_count == MASKED_COUNT_MAX) | |
1602 | goto do_query; | |
1603 | } | |
1604 | ||
1605 | do_query: | |
1606 | err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl, | |
1607 | &bulk_list, NULL, 0); | |
1608 | if (err) | |
1609 | goto out; | |
a759ab6d ST |
1610 | if (local_port < mlxsw_core_max_ports(mlxsw_core)) { |
1611 | local_port++; | |
2d0ed39f | 1612 | goto next_batch; |
a759ab6d | 1613 | } |
2d0ed39f JP |
1614 | |
1615 | out: | |
1616 | err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); | |
1617 | if (!err) | |
1618 | err = err2; | |
1619 | kfree(sbsr_pl); | |
1620 | return err; | |
1621 | } | |
1622 | ||
1623 | int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port, | |
1624 | unsigned int sb_index, u16 pool_index, | |
1625 | u32 *p_cur, u32 *p_max) | |
1626 | { | |
1627 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1628 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1629 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1630 | u8 local_port = mlxsw_sp_port->local_port; | |
2d0ed39f | 1631 | struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, |
3a4dbfb0 | 1632 | pool_index); |
2d0ed39f | 1633 | |
18281f2d IS |
1634 | *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur); |
1635 | *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max); | |
2d0ed39f JP |
1636 | return 0; |
1637 | } | |
1638 | ||
1639 | int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, | |
1640 | unsigned int sb_index, u16 tc_index, | |
1641 | enum devlink_sb_pool_type pool_type, | |
1642 | u32 *p_cur, u32 *p_max) | |
1643 | { | |
1644 | struct mlxsw_sp_port *mlxsw_sp_port = | |
1645 | mlxsw_core_port_driver_priv(mlxsw_core_port); | |
1646 | struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; | |
1647 | u8 local_port = mlxsw_sp_port->local_port; | |
1648 | u8 pg_buff = tc_index; | |
1a9234e6 | 1649 | enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type; |
2d0ed39f JP |
1650 | struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, |
1651 | pg_buff, dir); | |
1652 | ||
18281f2d IS |
1653 | *p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.cur); |
1654 | *p_max = mlxsw_sp_cells_bytes(mlxsw_sp, cm->occ.max); | |
2d0ed39f JP |
1655 | return 0; |
1656 | } |