blob: 3ab853db59eeba06abff2ed3487b236c62f2f4bb [file] [log] [blame]
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
3 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <linux/kernel.h>
36#include <linux/types.h>
Ido Schimmeldd6cb0f2016-04-06 17:10:01 +020037#include <linux/dcbnl.h>
Ido Schimmelff6551e2016-04-06 17:10:03 +020038#include <linux/if_ether.h>
Jiri Pirko2d0ed392016-04-14 18:19:30 +020039#include <linux/list.h>
Jiri Pirko56ade8f2015-10-16 14:01:37 +020040
41#include "spectrum.h"
42#include "core.h"
43#include "port.h"
44#include "reg.h"
45
Jiri Pirko078f9c72016-04-14 18:19:19 +020046static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
47 u8 pool,
48 enum mlxsw_reg_sbxx_dir dir)
49{
50 return &mlxsw_sp->sb.prs[dir][pool];
51}
52
53static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp,
54 u8 local_port, u8 pg_buff,
55 enum mlxsw_reg_sbxx_dir dir)
56{
57 return &mlxsw_sp->sb.ports[local_port].cms[dir][pg_buff];
58}
59
60static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp,
61 u8 local_port, u8 pool,
62 enum mlxsw_reg_sbxx_dir dir)
63{
64 return &mlxsw_sp->sb.ports[local_port].pms[dir][pool];
65}
66
Jiri Pirko94266e32016-04-14 18:19:16 +020067static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool,
68 enum mlxsw_reg_sbxx_dir dir,
69 enum mlxsw_reg_sbpr_mode mode, u32 size)
70{
71 char sbpr_pl[MLXSW_REG_SBPR_LEN];
Jiri Pirko078f9c72016-04-14 18:19:19 +020072 struct mlxsw_sp_sb_pr *pr;
73 int err;
Jiri Pirko94266e32016-04-14 18:19:16 +020074
75 mlxsw_reg_sbpr_pack(sbpr_pl, pool, dir, mode, size);
Jiri Pirko078f9c72016-04-14 18:19:19 +020076 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl);
77 if (err)
78 return err;
79
80 pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
81 pr->mode = mode;
82 pr->size = size;
83 return 0;
Jiri Pirko94266e32016-04-14 18:19:16 +020084}
85
86static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
87 u8 pg_buff, enum mlxsw_reg_sbxx_dir dir,
88 u32 min_buff, u32 max_buff, u8 pool)
89{
90 char sbcm_pl[MLXSW_REG_SBCM_LEN];
Jiri Pirko078f9c72016-04-14 18:19:19 +020091 int err;
Jiri Pirko94266e32016-04-14 18:19:16 +020092
93 mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, dir,
94 min_buff, max_buff, pool);
Jiri Pirko078f9c72016-04-14 18:19:19 +020095 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl);
96 if (err)
97 return err;
98 if (pg_buff < MLXSW_SP_SB_TC_COUNT) {
99 struct mlxsw_sp_sb_cm *cm;
100
101 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, dir);
102 cm->min_buff = min_buff;
103 cm->max_buff = max_buff;
104 cm->pool = pool;
105 }
106 return 0;
Jiri Pirko94266e32016-04-14 18:19:16 +0200107}
108
109static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
110 u8 pool, enum mlxsw_reg_sbxx_dir dir,
111 u32 min_buff, u32 max_buff)
112{
113 char sbpm_pl[MLXSW_REG_SBPM_LEN];
Jiri Pirko078f9c72016-04-14 18:19:19 +0200114 struct mlxsw_sp_sb_pm *pm;
115 int err;
Jiri Pirko94266e32016-04-14 18:19:16 +0200116
Jiri Pirko42a7f1d2016-04-14 18:19:27 +0200117 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false,
118 min_buff, max_buff);
Jiri Pirko078f9c72016-04-14 18:19:19 +0200119 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl);
120 if (err)
121 return err;
122
123 pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir);
124 pm->min_buff = min_buff;
125 pm->max_buff = max_buff;
126 return 0;
Jiri Pirko94266e32016-04-14 18:19:16 +0200127}
128
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200129static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
130 u8 pool, enum mlxsw_reg_sbxx_dir dir,
131 struct list_head *bulk_list)
132{
133 char sbpm_pl[MLXSW_REG_SBPM_LEN];
134
135 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, true, 0, 0);
136 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
137 bulk_list, NULL, 0);
138}
139
140static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core,
141 char *sbpm_pl, size_t sbpm_pl_len,
142 unsigned long cb_priv)
143{
144 struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv;
145
146 mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max);
147}
148
149static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
150 u8 pool, enum mlxsw_reg_sbxx_dir dir,
151 struct list_head *bulk_list)
152{
153 char sbpm_pl[MLXSW_REG_SBPM_LEN];
154 struct mlxsw_sp_sb_pm *pm;
155
156 pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir);
157 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 0, 0);
158 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
159 bulk_list,
160 mlxsw_sp_sb_pm_occ_query_cb,
161 (unsigned long) pm);
162}
163
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200164static const u16 mlxsw_sp_pbs[] = {
Jiri Pirkoce78f022016-04-15 15:09:37 +0200165 [0] = 2 * MLXSW_SP_BYTES_TO_CELLS(ETH_FRAME_LEN),
166 [9] = 2 * MLXSW_SP_BYTES_TO_CELLS(MLXSW_PORT_MAX_MTU),
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200167};
168
169#define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs)
Jiri Pirkob94cdab2016-04-15 15:09:38 +0200170#define MLXSW_SP_PB_UNUSED 8
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200171
172static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port)
173{
174 char pbmc_pl[MLXSW_REG_PBMC_LEN];
175 int i;
176
177 mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port,
178 0xffff, 0xffff / 2);
179 for (i = 0; i < MLXSW_SP_PBS_LEN; i++) {
Jiri Pirkob94cdab2016-04-15 15:09:38 +0200180 if (i == MLXSW_SP_PB_UNUSED)
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200181 continue;
182 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, i, mlxsw_sp_pbs[i]);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200183 }
Ido Schimmeld6b7c132016-04-06 17:10:05 +0200184 mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl,
185 MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200186 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core,
187 MLXSW_REG(pbmc), pbmc_pl);
188}
189
Ido Schimmeldd6cb0f2016-04-06 17:10:01 +0200190static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port *mlxsw_sp_port)
191{
192 char pptb_pl[MLXSW_REG_PPTB_LEN];
193 int i;
194
195 mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port);
196 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
Ido Schimmel11719a52016-07-15 11:15:02 +0200197 mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, i, 0);
Ido Schimmeldd6cb0f2016-04-06 17:10:01 +0200198 return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb),
199 pptb_pl);
200}
201
202static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
203{
204 int err;
205
206 err = mlxsw_sp_port_pb_init(mlxsw_sp_port);
207 if (err)
208 return err;
209 return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port);
210}
211
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100212static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp)
213{
214 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
215
216 mlxsw_sp->sb.ports = kcalloc(max_ports, sizeof(struct mlxsw_sp_sb_port),
217 GFP_KERNEL);
218 if (!mlxsw_sp->sb.ports)
219 return -ENOMEM;
220 return 0;
221}
222
223static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
224{
225 kfree(mlxsw_sp->sb.ports);
226}
227
228#define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000
Jiri Pirkobc872502016-04-14 18:19:21 +0200229#define MLXSW_SP_SB_PR_INGRESS_MNG_SIZE (200 * 1000)
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100230#define MLXSW_SP_SB_PR_EGRESS_SIZE 13232000
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200231
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200232#define MLXSW_SP_SB_PR(_mode, _size) \
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200233 { \
234 .mode = _mode, \
235 .size = _size, \
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200236 }
237
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200238static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_ingress[] = {
239 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
240 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_INGRESS_SIZE)),
241 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
242 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
Jiri Pirkobc872502016-04-14 18:19:21 +0200243 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
244 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_INGRESS_MNG_SIZE)),
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200245};
246
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200247#define MLXSW_SP_SB_PRS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_ingress)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200248
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200249static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_egress[] = {
250 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
251 MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_PR_EGRESS_SIZE)),
252 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
253 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
Jiri Pirko5408f7c2016-04-14 18:19:20 +0200254 MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200255};
256
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200257#define MLXSW_SP_SB_PRS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_egress)
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200258
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200259static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
260 enum mlxsw_reg_sbxx_dir dir,
261 const struct mlxsw_sp_sb_pr *prs,
262 size_t prs_len)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200263{
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200264 int i;
265 int err;
266
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200267 for (i = 0; i < prs_len; i++) {
268 const struct mlxsw_sp_sb_pr *pr;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200269
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200270 pr = &prs[i];
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200271 err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, dir,
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200272 pr->mode, pr->size);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200273 if (err)
274 return err;
275 }
276 return 0;
277}
278
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200279static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp)
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200280{
281 int err;
282
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200283 err = __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_INGRESS,
284 mlxsw_sp_sb_prs_ingress,
285 MLXSW_SP_SB_PRS_INGRESS_LEN);
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200286 if (err)
287 return err;
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200288 return __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_EGRESS,
289 mlxsw_sp_sb_prs_egress,
290 MLXSW_SP_SB_PRS_EGRESS_LEN);
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200291}
292
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200293#define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \
294 { \
295 .min_buff = _min_buff, \
296 .max_buff = _max_buff, \
297 .pool = _pool, \
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200298 }
299
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200300static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
301 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(10000), 8, 0),
Jiri Pirkoc30a53c2016-04-14 18:19:22 +0200302 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
303 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
304 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
305 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
306 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
307 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
308 MLXSW_SP_SB_CM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN, 0),
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200309 MLXSW_SP_SB_CM(0, 0, 0), /* dummy, this PG does not exist */
Jiri Pirkobc872502016-04-14 18:19:21 +0200310 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(20000), 1, 3),
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200311};
312
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200313#define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress)
314
315static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
316 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
317 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
318 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
319 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
320 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
321 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
322 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
323 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(1500), 9, 0),
324 MLXSW_SP_SB_CM(0, 0, 0),
325 MLXSW_SP_SB_CM(0, 0, 0),
326 MLXSW_SP_SB_CM(0, 0, 0),
327 MLXSW_SP_SB_CM(0, 0, 0),
328 MLXSW_SP_SB_CM(0, 0, 0),
329 MLXSW_SP_SB_CM(0, 0, 0),
330 MLXSW_SP_SB_CM(0, 0, 0),
331 MLXSW_SP_SB_CM(0, 0, 0),
332 MLXSW_SP_SB_CM(1, 0xff, 0),
333};
334
335#define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress)
336
Jiri Pirko5408f7c2016-04-14 18:19:20 +0200337#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 0)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200338
339static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200340 MLXSW_SP_CPU_PORT_SB_CM,
341 MLXSW_SP_CPU_PORT_SB_CM,
342 MLXSW_SP_CPU_PORT_SB_CM,
343 MLXSW_SP_CPU_PORT_SB_CM,
344 MLXSW_SP_CPU_PORT_SB_CM,
345 MLXSW_SP_CPU_PORT_SB_CM,
346 MLXSW_SP_CPU_PORT_SB_CM,
Ido Schimmel9ffcc372016-08-17 16:39:37 +0200347 MLXSW_SP_SB_CM(MLXSW_SP_BYTES_TO_CELLS(10000), 0, 0),
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200348 MLXSW_SP_CPU_PORT_SB_CM,
349 MLXSW_SP_CPU_PORT_SB_CM,
350 MLXSW_SP_CPU_PORT_SB_CM,
351 MLXSW_SP_CPU_PORT_SB_CM,
352 MLXSW_SP_CPU_PORT_SB_CM,
353 MLXSW_SP_CPU_PORT_SB_CM,
354 MLXSW_SP_CPU_PORT_SB_CM,
355 MLXSW_SP_CPU_PORT_SB_CM,
356 MLXSW_SP_CPU_PORT_SB_CM,
357 MLXSW_SP_CPU_PORT_SB_CM,
358 MLXSW_SP_CPU_PORT_SB_CM,
359 MLXSW_SP_CPU_PORT_SB_CM,
360 MLXSW_SP_CPU_PORT_SB_CM,
361 MLXSW_SP_CPU_PORT_SB_CM,
362 MLXSW_SP_CPU_PORT_SB_CM,
363 MLXSW_SP_CPU_PORT_SB_CM,
364 MLXSW_SP_CPU_PORT_SB_CM,
365 MLXSW_SP_CPU_PORT_SB_CM,
366 MLXSW_SP_CPU_PORT_SB_CM,
367 MLXSW_SP_CPU_PORT_SB_CM,
368 MLXSW_SP_CPU_PORT_SB_CM,
369 MLXSW_SP_CPU_PORT_SB_CM,
370 MLXSW_SP_CPU_PORT_SB_CM,
371 MLXSW_SP_CPU_PORT_SB_CM,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200372};
373
374#define MLXSW_SP_CPU_PORT_SB_MCS_LEN \
375 ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms)
376
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200377static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
378 enum mlxsw_reg_sbxx_dir dir,
379 const struct mlxsw_sp_sb_cm *cms,
380 size_t cms_len)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200381{
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200382 int i;
383 int err;
384
385 for (i = 0; i < cms_len; i++) {
386 const struct mlxsw_sp_sb_cm *cm;
387
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200388 if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS)
389 continue; /* PG number 8 does not exist, skip it */
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200390 cm = &cms[i];
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200391 err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, dir,
392 cm->min_buff, cm->max_buff,
393 cm->pool);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200394 if (err)
395 return err;
396 }
397 return 0;
398}
399
400static int mlxsw_sp_port_sb_cms_init(struct mlxsw_sp_port *mlxsw_sp_port)
401{
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200402 int err;
403
404 err = __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
405 mlxsw_sp_port->local_port,
406 MLXSW_REG_SBXX_DIR_INGRESS,
407 mlxsw_sp_sb_cms_ingress,
408 MLXSW_SP_SB_CMS_INGRESS_LEN);
409 if (err)
410 return err;
411 return __mlxsw_sp_sb_cms_init(mlxsw_sp_port->mlxsw_sp,
412 mlxsw_sp_port->local_port,
413 MLXSW_REG_SBXX_DIR_EGRESS,
414 mlxsw_sp_sb_cms_egress,
415 MLXSW_SP_SB_CMS_EGRESS_LEN);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200416}
417
418static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
419{
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200420 return __mlxsw_sp_sb_cms_init(mlxsw_sp, 0, MLXSW_REG_SBXX_DIR_EGRESS,
421 mlxsw_sp_cpu_port_sb_cms,
422 MLXSW_SP_CPU_PORT_SB_MCS_LEN);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200423}
424
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200425#define MLXSW_SP_SB_PM(_min_buff, _max_buff) \
426 { \
427 .min_buff = _min_buff, \
428 .max_buff = _max_buff, \
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200429 }
430
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200431static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_ingress[] = {
Jiri Pirkoc30a53c2016-04-14 18:19:22 +0200432 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
433 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
434 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
435 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200436};
437
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200438#define MLXSW_SP_SB_PMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_ingress)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200439
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200440static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_egress[] = {
441 MLXSW_SP_SB_PM(0, 7),
Jiri Pirkoc30a53c2016-04-14 18:19:22 +0200442 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
443 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
444 MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200445};
446
447#define MLXSW_SP_SB_PMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_egress)
448
449static int __mlxsw_sp_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
450 enum mlxsw_reg_sbxx_dir dir,
451 const struct mlxsw_sp_sb_pm *pms,
452 size_t pms_len)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200453{
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200454 int i;
455 int err;
456
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200457 for (i = 0; i < pms_len; i++) {
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200458 const struct mlxsw_sp_sb_pm *pm;
459
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200460 pm = &pms[i];
461 err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, dir,
Jiri Pirko94266e32016-04-14 18:19:16 +0200462 pm->min_buff, pm->max_buff);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200463 if (err)
464 return err;
465 }
466 return 0;
467}
468
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200469static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
470{
471 int err;
472
473 err = __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp,
474 mlxsw_sp_port->local_port,
475 MLXSW_REG_SBXX_DIR_INGRESS,
476 mlxsw_sp_sb_pms_ingress,
477 MLXSW_SP_SB_PMS_INGRESS_LEN);
478 if (err)
479 return err;
480 return __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp,
481 mlxsw_sp_port->local_port,
482 MLXSW_REG_SBXX_DIR_EGRESS,
483 mlxsw_sp_sb_pms_egress,
484 MLXSW_SP_SB_PMS_EGRESS_LEN);
485}
486
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200487struct mlxsw_sp_sb_mm {
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200488 u32 min_buff;
489 u32 max_buff;
490 u8 pool;
491};
492
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200493#define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \
494 { \
495 .min_buff = _min_buff, \
496 .max_buff = _max_buff, \
497 .pool = _pool, \
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200498 }
499
500static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200501 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
502 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
503 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
504 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
505 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
506 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
507 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
508 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
509 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
510 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
511 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
512 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
513 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
514 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
515 MLXSW_SP_SB_MM(MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200516};
517
518#define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
519
520static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
521{
522 char sbmm_pl[MLXSW_REG_SBMM_LEN];
523 int i;
524 int err;
525
526 for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) {
527 const struct mlxsw_sp_sb_mm *mc;
528
529 mc = &mlxsw_sp_sb_mms[i];
Jiri Pirkob11c3b42016-04-14 18:19:17 +0200530 mlxsw_reg_sbmm_pack(sbmm_pl, i, mc->min_buff,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200531 mc->max_buff, mc->pool);
532 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl);
533 if (err)
534 return err;
535 }
536 return 0;
537}
538
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200539#define MLXSW_SP_SB_SIZE (16 * 1024 * 1024)
540
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200541int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
542{
543 int err;
544
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100545 err = mlxsw_sp_sb_ports_init(mlxsw_sp);
546 if (err)
547 return err;
Jiri Pirkoaa99bc72016-04-14 18:19:18 +0200548 err = mlxsw_sp_sb_prs_init(mlxsw_sp);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200549 if (err)
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100550 goto err_sb_prs_init;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200551 err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp);
552 if (err)
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100553 goto err_sb_cpu_port_sb_cms_init;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200554 err = mlxsw_sp_sb_mms_init(mlxsw_sp);
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200555 if (err)
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100556 goto err_sb_mms_init;
557 err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0,
558 MLXSW_SP_SB_SIZE,
559 MLXSW_SP_SB_POOL_COUNT,
560 MLXSW_SP_SB_POOL_COUNT,
561 MLXSW_SP_SB_TC_COUNT,
562 MLXSW_SP_SB_TC_COUNT);
563 if (err)
564 goto err_devlink_sb_register;
565
566 return 0;
567
568err_devlink_sb_register:
569err_sb_mms_init:
570err_sb_cpu_port_sb_cms_init:
571err_sb_prs_init:
572 mlxsw_sp_sb_ports_fini(mlxsw_sp);
573 return err;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200574}
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200575
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200576void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp)
577{
578 devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0);
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100579 mlxsw_sp_sb_ports_fini(mlxsw_sp);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200580}
581
582int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port)
583{
584 int err;
585
Ido Schimmeldd6cb0f2016-04-06 17:10:01 +0200586 err = mlxsw_sp_port_headroom_init(mlxsw_sp_port);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200587 if (err)
588 return err;
589 err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port);
590 if (err)
591 return err;
592 err = mlxsw_sp_port_sb_pms_init(mlxsw_sp_port);
593
594 return err;
595}
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200596
597static u8 pool_get(u16 pool_index)
598{
599 return pool_index % MLXSW_SP_SB_POOL_COUNT;
600}
601
602static u16 pool_index_get(u8 pool, enum mlxsw_reg_sbxx_dir dir)
603{
604 u16 pool_index;
605
606 pool_index = pool;
607 if (dir == MLXSW_REG_SBXX_DIR_EGRESS)
608 pool_index += MLXSW_SP_SB_POOL_COUNT;
609 return pool_index;
610}
611
612static enum mlxsw_reg_sbxx_dir dir_get(u16 pool_index)
613{
614 return pool_index < MLXSW_SP_SB_POOL_COUNT ?
615 MLXSW_REG_SBXX_DIR_INGRESS : MLXSW_REG_SBXX_DIR_EGRESS;
616}
617
618int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
619 unsigned int sb_index, u16 pool_index,
620 struct devlink_sb_pool_info *pool_info)
621{
622 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
623 u8 pool = pool_get(pool_index);
624 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
625 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
626
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200627 pool_info->pool_type = (enum devlink_sb_pool_type) dir;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200628 pool_info->size = MLXSW_SP_CELLS_TO_BYTES(pr->size);
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200629 pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200630 return 0;
631}
632
633int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core,
634 unsigned int sb_index, u16 pool_index, u32 size,
635 enum devlink_sb_threshold_type threshold_type)
636{
637 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
638 u8 pool = pool_get(pool_index);
639 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200640 u32 pool_size = MLXSW_SP_BYTES_TO_CELLS(size);
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200641 enum mlxsw_reg_sbpr_mode mode;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200642
Ido Schimmel87259f12016-11-28 18:01:24 +0100643 if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE))
644 return -EINVAL;
645
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200646 mode = (enum mlxsw_reg_sbpr_mode) threshold_type;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200647 return mlxsw_sp_sb_pr_write(mlxsw_sp, pool, dir, mode, pool_size);
648}
649
650#define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */
651
652static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u8 pool,
653 enum mlxsw_reg_sbxx_dir dir, u32 max_buff)
654{
655 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
656
657 if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC)
658 return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET;
659 return MLXSW_SP_CELLS_TO_BYTES(max_buff);
660}
661
662static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u8 pool,
663 enum mlxsw_reg_sbxx_dir dir, u32 threshold,
664 u32 *p_max_buff)
665{
666 struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
667
668 if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) {
669 int val;
670
671 val = threshold + MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET;
672 if (val < MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN ||
673 val > MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX)
674 return -EINVAL;
675 *p_max_buff = val;
676 } else {
677 *p_max_buff = MLXSW_SP_BYTES_TO_CELLS(threshold);
678 }
679 return 0;
680}
681
682int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
683 unsigned int sb_index, u16 pool_index,
684 u32 *p_threshold)
685{
686 struct mlxsw_sp_port *mlxsw_sp_port =
687 mlxsw_core_port_driver_priv(mlxsw_core_port);
688 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
689 u8 local_port = mlxsw_sp_port->local_port;
690 u8 pool = pool_get(pool_index);
691 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
692 struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
693 pool, dir);
694
695 *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool, dir,
696 pm->max_buff);
697 return 0;
698}
699
700int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port,
701 unsigned int sb_index, u16 pool_index,
702 u32 threshold)
703{
704 struct mlxsw_sp_port *mlxsw_sp_port =
705 mlxsw_core_port_driver_priv(mlxsw_core_port);
706 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
707 u8 local_port = mlxsw_sp_port->local_port;
708 u8 pool = pool_get(pool_index);
709 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
710 u32 max_buff;
711 int err;
712
713 err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir,
714 threshold, &max_buff);
715 if (err)
716 return err;
717
718 return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool, dir,
719 0, max_buff);
720}
721
722int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port,
723 unsigned int sb_index, u16 tc_index,
724 enum devlink_sb_pool_type pool_type,
725 u16 *p_pool_index, u32 *p_threshold)
726{
727 struct mlxsw_sp_port *mlxsw_sp_port =
728 mlxsw_core_port_driver_priv(mlxsw_core_port);
729 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
730 u8 local_port = mlxsw_sp_port->local_port;
731 u8 pg_buff = tc_index;
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200732 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200733 struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
734 pg_buff, dir);
735
736 *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool, dir,
737 cm->max_buff);
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200738 *p_pool_index = pool_index_get(cm->pool, dir);
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200739 return 0;
740}
741
742int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
743 unsigned int sb_index, u16 tc_index,
744 enum devlink_sb_pool_type pool_type,
745 u16 pool_index, u32 threshold)
746{
747 struct mlxsw_sp_port *mlxsw_sp_port =
748 mlxsw_core_port_driver_priv(mlxsw_core_port);
749 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
750 u8 local_port = mlxsw_sp_port->local_port;
751 u8 pg_buff = tc_index;
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200752 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
Jiri Pirko89128622016-08-19 14:43:48 +0200753 u8 pool = pool_get(pool_index);
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200754 u32 max_buff;
755 int err;
756
Jiri Pirko89128622016-08-19 14:43:48 +0200757 if (dir != dir_get(pool_index))
758 return -EINVAL;
759
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200760 err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir,
761 threshold, &max_buff);
762 if (err)
763 return err;
764
Jiri Pirko0f433fa2016-04-14 18:19:24 +0200765 return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir,
766 0, max_buff, pool);
767}
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200768
769#define MASKED_COUNT_MAX \
770 (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2))
771
772struct mlxsw_sp_sb_sr_occ_query_cb_ctx {
773 u8 masked_count;
774 u8 local_port_1;
775};
776
777static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
778 char *sbsr_pl, size_t sbsr_pl_len,
779 unsigned long cb_priv)
780{
781 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
782 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
783 u8 masked_count;
784 u8 local_port;
785 int rec_index = 0;
786 struct mlxsw_sp_sb_cm *cm;
787 int i;
788
789 memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx));
790
791 masked_count = 0;
792 for (local_port = cb_ctx.local_port_1;
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100793 local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200794 if (!mlxsw_sp->ports[local_port])
795 continue;
796 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
797 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
798 MLXSW_REG_SBXX_DIR_INGRESS);
799 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
800 &cm->occ.cur, &cm->occ.max);
801 }
802 if (++masked_count == cb_ctx.masked_count)
803 break;
804 }
805 masked_count = 0;
806 for (local_port = cb_ctx.local_port_1;
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100807 local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200808 if (!mlxsw_sp->ports[local_port])
809 continue;
810 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
811 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
812 MLXSW_REG_SBXX_DIR_EGRESS);
813 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
814 &cm->occ.cur, &cm->occ.max);
815 }
816 if (++masked_count == cb_ctx.masked_count)
817 break;
818 }
819}
820
821int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
822 unsigned int sb_index)
823{
824 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
825 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
826 unsigned long cb_priv;
827 LIST_HEAD(bulk_list);
828 char *sbsr_pl;
829 u8 masked_count;
830 u8 local_port_1;
831 u8 local_port = 0;
832 int i;
833 int err;
834 int err2;
835
836 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
837 if (!sbsr_pl)
838 return -ENOMEM;
839
840next_batch:
841 local_port++;
842 local_port_1 = local_port;
843 masked_count = 0;
844 mlxsw_reg_sbsr_pack(sbsr_pl, false);
845 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
846 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
847 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
848 }
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100849 for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200850 if (!mlxsw_sp->ports[local_port])
851 continue;
852 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
853 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
854 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
855 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
856 MLXSW_REG_SBXX_DIR_INGRESS,
857 &bulk_list);
858 if (err)
859 goto out;
860 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
861 MLXSW_REG_SBXX_DIR_EGRESS,
862 &bulk_list);
863 if (err)
864 goto out;
865 }
866 if (++masked_count == MASKED_COUNT_MAX)
867 goto do_query;
868 }
869
870do_query:
871 cb_ctx.masked_count = masked_count;
872 cb_ctx.local_port_1 = local_port_1;
873 memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx));
874 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
875 &bulk_list, mlxsw_sp_sb_sr_occ_query_cb,
876 cb_priv);
877 if (err)
878 goto out;
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100879 if (local_port < mlxsw_core_max_ports(mlxsw_core))
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200880 goto next_batch;
881
882out:
883 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
884 if (!err)
885 err = err2;
886 kfree(sbsr_pl);
887 return err;
888}
889
890int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
891 unsigned int sb_index)
892{
893 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
894 LIST_HEAD(bulk_list);
895 char *sbsr_pl;
896 unsigned int masked_count;
897 u8 local_port = 0;
898 int i;
899 int err;
900 int err2;
901
902 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
903 if (!sbsr_pl)
904 return -ENOMEM;
905
906next_batch:
907 local_port++;
908 masked_count = 0;
909 mlxsw_reg_sbsr_pack(sbsr_pl, true);
910 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
911 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
912 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
913 }
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100914 for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200915 if (!mlxsw_sp->ports[local_port])
916 continue;
917 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
918 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
919 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
920 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
921 MLXSW_REG_SBXX_DIR_INGRESS,
922 &bulk_list);
923 if (err)
924 goto out;
925 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
926 MLXSW_REG_SBXX_DIR_EGRESS,
927 &bulk_list);
928 if (err)
929 goto out;
930 }
931 if (++masked_count == MASKED_COUNT_MAX)
932 goto do_query;
933 }
934
935do_query:
936 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
937 &bulk_list, NULL, 0);
938 if (err)
939 goto out;
Ido Schimmel5ec2ee72017-03-24 08:02:48 +0100940 if (local_port < mlxsw_core_max_ports(mlxsw_core))
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200941 goto next_batch;
942
943out:
944 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
945 if (!err)
946 err = err2;
947 kfree(sbsr_pl);
948 return err;
949}
950
951int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
952 unsigned int sb_index, u16 pool_index,
953 u32 *p_cur, u32 *p_max)
954{
955 struct mlxsw_sp_port *mlxsw_sp_port =
956 mlxsw_core_port_driver_priv(mlxsw_core_port);
957 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
958 u8 local_port = mlxsw_sp_port->local_port;
959 u8 pool = pool_get(pool_index);
960 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
961 struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
962 pool, dir);
963
964 *p_cur = MLXSW_SP_CELLS_TO_BYTES(pm->occ.cur);
965 *p_max = MLXSW_SP_CELLS_TO_BYTES(pm->occ.max);
966 return 0;
967}
968
969int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
970 unsigned int sb_index, u16 tc_index,
971 enum devlink_sb_pool_type pool_type,
972 u32 *p_cur, u32 *p_max)
973{
974 struct mlxsw_sp_port *mlxsw_sp_port =
975 mlxsw_core_port_driver_priv(mlxsw_core_port);
976 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
977 u8 local_port = mlxsw_sp_port->local_port;
978 u8 pg_buff = tc_index;
Ido Schimmel1a9234e662016-09-19 08:29:26 +0200979 enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
Jiri Pirko2d0ed392016-04-14 18:19:30 +0200980 struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
981 pg_buff, dir);
982
983 *p_cur = MLXSW_SP_CELLS_TO_BYTES(cm->occ.cur);
984 *p_max = MLXSW_SP_CELLS_TO_BYTES(cm->occ.max);
985 return 0;
986}