1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/netdevice.h>
5*4882a593Smuzhiyun #include <linux/string.h>
6*4882a593Smuzhiyun #include <linux/bitops.h>
7*4882a593Smuzhiyun #include <net/dcbnl.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "spectrum.h"
10*4882a593Smuzhiyun #include "reg.h"
11*4882a593Smuzhiyun
mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused * dev)12*4882a593Smuzhiyun static u8 mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused *dev)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
15*4882a593Smuzhiyun }
16*4882a593Smuzhiyun
mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused * dev,u8 mode)17*4882a593Smuzhiyun static u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
18*4882a593Smuzhiyun u8 mode)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_getets(struct net_device * dev,struct ieee_ets * ets)23*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_getets(struct net_device *dev,
24*4882a593Smuzhiyun struct ieee_ets *ets)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun memcpy(ets, mlxsw_sp_port->dcb.ets, sizeof(*ets));
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun return 0;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
mlxsw_sp_port_ets_validate(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)33*4882a593Smuzhiyun static int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port,
34*4882a593Smuzhiyun struct ieee_ets *ets)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
37*4882a593Smuzhiyun bool has_ets_tc = false;
38*4882a593Smuzhiyun int i, tx_bw_sum = 0;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
41*4882a593Smuzhiyun switch (ets->tc_tsa[i]) {
42*4882a593Smuzhiyun case IEEE_8021QAZ_TSA_STRICT:
43*4882a593Smuzhiyun break;
44*4882a593Smuzhiyun case IEEE_8021QAZ_TSA_ETS:
45*4882a593Smuzhiyun has_ets_tc = true;
46*4882a593Smuzhiyun tx_bw_sum += ets->tc_tx_bw[i];
47*4882a593Smuzhiyun break;
48*4882a593Smuzhiyun default:
49*4882a593Smuzhiyun netdev_err(dev, "Only strict priority and ETS are supported\n");
50*4882a593Smuzhiyun return -EINVAL;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (ets->prio_tc[i] >= IEEE_8021QAZ_MAX_TCS) {
54*4882a593Smuzhiyun netdev_err(dev, "Invalid TC\n");
55*4882a593Smuzhiyun return -EINVAL;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (has_ets_tc && tx_bw_sum != 100) {
60*4882a593Smuzhiyun netdev_err(dev, "Total ETS bandwidth should equal 100\n");
61*4882a593Smuzhiyun return -EINVAL;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)67*4882a593Smuzhiyun static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
68*4882a593Smuzhiyun struct ieee_ets *ets)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
71*4882a593Smuzhiyun struct mlxsw_sp_hdroom hdroom;
72*4882a593Smuzhiyun int prio;
73*4882a593Smuzhiyun int err;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun hdroom = *mlxsw_sp_port->hdroom;
76*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
77*4882a593Smuzhiyun hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio];
78*4882a593Smuzhiyun mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
79*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
80*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
83*4882a593Smuzhiyun if (err) {
84*4882a593Smuzhiyun netdev_err(dev, "Failed to configure port's headroom\n");
85*4882a593Smuzhiyun return err;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
__mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)91*4882a593Smuzhiyun static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
92*4882a593Smuzhiyun struct ieee_ets *ets)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun struct ieee_ets *my_ets = mlxsw_sp_port->dcb.ets;
95*4882a593Smuzhiyun struct net_device *dev = mlxsw_sp_port->dev;
96*4882a593Smuzhiyun int i, err;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Egress configuration. */
99*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
100*4882a593Smuzhiyun bool dwrr = ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
101*4882a593Smuzhiyun u8 weight = ets->tc_tx_bw[i];
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
104*4882a593Smuzhiyun MLXSW_REG_QEEC_HR_SUBGROUP, i,
105*4882a593Smuzhiyun 0, dwrr, weight);
106*4882a593Smuzhiyun if (err) {
107*4882a593Smuzhiyun netdev_err(dev, "Failed to link subgroup ETS element %d to group\n",
108*4882a593Smuzhiyun i);
109*4882a593Smuzhiyun goto err_port_ets_set;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
114*4882a593Smuzhiyun err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
115*4882a593Smuzhiyun ets->prio_tc[i]);
116*4882a593Smuzhiyun if (err) {
117*4882a593Smuzhiyun netdev_err(dev, "Failed to map prio %d to TC %d\n", i,
118*4882a593Smuzhiyun ets->prio_tc[i]);
119*4882a593Smuzhiyun goto err_port_prio_tc_set;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* Ingress configuration. */
124*4882a593Smuzhiyun err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets);
125*4882a593Smuzhiyun if (err)
126*4882a593Smuzhiyun goto err_port_headroom_set;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun err_port_headroom_set:
131*4882a593Smuzhiyun i = IEEE_8021QAZ_MAX_TCS;
132*4882a593Smuzhiyun err_port_prio_tc_set:
133*4882a593Smuzhiyun for (i--; i >= 0; i--)
134*4882a593Smuzhiyun mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, my_ets->prio_tc[i]);
135*4882a593Smuzhiyun i = IEEE_8021QAZ_MAX_TCS;
136*4882a593Smuzhiyun err_port_ets_set:
137*4882a593Smuzhiyun for (i--; i >= 0; i--) {
138*4882a593Smuzhiyun bool dwrr = my_ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
139*4882a593Smuzhiyun u8 weight = my_ets->tc_tx_bw[i];
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
142*4882a593Smuzhiyun MLXSW_REG_QEEC_HR_SUBGROUP, i,
143*4882a593Smuzhiyun 0, dwrr, weight);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun return err;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_setets(struct net_device * dev,struct ieee_ets * ets)148*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_setets(struct net_device *dev,
149*4882a593Smuzhiyun struct ieee_ets *ets)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
152*4882a593Smuzhiyun int err;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun err = mlxsw_sp_port_ets_validate(mlxsw_sp_port, ets);
155*4882a593Smuzhiyun if (err)
156*4882a593Smuzhiyun return err;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun err = __mlxsw_sp_dcbnl_ieee_setets(mlxsw_sp_port, ets);
159*4882a593Smuzhiyun if (err)
160*4882a593Smuzhiyun return err;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun memcpy(mlxsw_sp_port->dcb.ets, ets, sizeof(*ets));
163*4882a593Smuzhiyun mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
mlxsw_sp_dcbnl_app_validate(struct net_device * dev,struct dcb_app * app)168*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_app_validate(struct net_device *dev,
169*4882a593Smuzhiyun struct dcb_app *app)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun if (app->priority >= IEEE_8021QAZ_MAX_TCS) {
172*4882a593Smuzhiyun netdev_err(dev, "APP entry with priority value %u is invalid\n",
173*4882a593Smuzhiyun app->priority);
174*4882a593Smuzhiyun return -EINVAL;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun switch (app->selector) {
178*4882a593Smuzhiyun case IEEE_8021QAZ_APP_SEL_DSCP:
179*4882a593Smuzhiyun if (app->protocol >= 64) {
180*4882a593Smuzhiyun netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n",
181*4882a593Smuzhiyun app->protocol);
182*4882a593Smuzhiyun return -EINVAL;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
187*4882a593Smuzhiyun if (app->protocol) {
188*4882a593Smuzhiyun netdev_err(dev, "EtherType APP entries with protocol value != 0 not supported\n");
189*4882a593Smuzhiyun return -EINVAL;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun break;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun default:
194*4882a593Smuzhiyun netdev_err(dev, "APP entries with selector %u not supported\n",
195*4882a593Smuzhiyun app->selector);
196*4882a593Smuzhiyun return -EINVAL;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun return 0;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun static u8
mlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port * mlxsw_sp_port)203*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port *mlxsw_sp_port)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun u8 prio_mask;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun prio_mask = dcb_ieee_getapp_default_prio_mask(mlxsw_sp_port->dev);
208*4882a593Smuzhiyun if (prio_mask)
209*4882a593Smuzhiyun /* Take the highest configured priority. */
210*4882a593Smuzhiyun return fls(prio_mask) - 1;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun static void
mlxsw_sp_port_dcb_app_dscp_prio_map(struct mlxsw_sp_port * mlxsw_sp_port,u8 default_prio,struct dcb_ieee_app_dscp_map * map)216*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_dscp_prio_map(struct mlxsw_sp_port *mlxsw_sp_port,
217*4882a593Smuzhiyun u8 default_prio,
218*4882a593Smuzhiyun struct dcb_ieee_app_dscp_map *map)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun int i;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun dcb_ieee_getapp_dscp_prio_mask_map(mlxsw_sp_port->dev, map);
223*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
224*4882a593Smuzhiyun if (map->map[i])
225*4882a593Smuzhiyun map->map[i] = fls(map->map[i]) - 1;
226*4882a593Smuzhiyun else
227*4882a593Smuzhiyun map->map[i] = default_prio;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun static bool
mlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_prio_map * map)232*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port *mlxsw_sp_port,
233*4882a593Smuzhiyun struct dcb_ieee_app_prio_map *map)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun bool have_dscp = false;
236*4882a593Smuzhiyun int i;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun dcb_ieee_getapp_prio_dscp_mask_map(mlxsw_sp_port->dev, map);
239*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
240*4882a593Smuzhiyun if (map->map[i]) {
241*4882a593Smuzhiyun map->map[i] = fls64(map->map[i]) - 1;
242*4882a593Smuzhiyun have_dscp = true;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun return have_dscp;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qpts_trust_state ts)250*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port *mlxsw_sp_port,
251*4882a593Smuzhiyun enum mlxsw_reg_qpts_trust_state ts)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
254*4882a593Smuzhiyun char qpts_pl[MLXSW_REG_QPTS_LEN];
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun mlxsw_reg_qpts_pack(qpts_pl, mlxsw_sp_port->local_port, ts);
257*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpts), qpts_pl);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port * mlxsw_sp_port,bool rewrite_dscp)261*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port *mlxsw_sp_port,
262*4882a593Smuzhiyun bool rewrite_dscp)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
265*4882a593Smuzhiyun char qrwe_pl[MLXSW_REG_QRWE_LEN];
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun mlxsw_reg_qrwe_pack(qrwe_pl, mlxsw_sp_port->local_port,
268*4882a593Smuzhiyun false, rewrite_dscp);
269*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qrwe), qrwe_pl);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qpts_trust_state ts)273*4882a593Smuzhiyun mlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port *mlxsw_sp_port,
274*4882a593Smuzhiyun enum mlxsw_reg_qpts_trust_state ts)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun bool rewrite_dscp = ts == MLXSW_REG_QPTS_TRUST_STATE_DSCP;
277*4882a593Smuzhiyun int err;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (mlxsw_sp_port->dcb.trust_state == ts)
280*4882a593Smuzhiyun return 0;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port, ts);
283*4882a593Smuzhiyun if (err)
284*4882a593Smuzhiyun return err;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update_qrwe(mlxsw_sp_port, rewrite_dscp);
287*4882a593Smuzhiyun if (err)
288*4882a593Smuzhiyun goto err_update_qrwe;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun mlxsw_sp_port->dcb.trust_state = ts;
291*4882a593Smuzhiyun return 0;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun err_update_qrwe:
294*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port,
295*4882a593Smuzhiyun mlxsw_sp_port->dcb.trust_state);
296*4882a593Smuzhiyun return err;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port * mlxsw_sp_port,u8 default_prio)300*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port *mlxsw_sp_port,
301*4882a593Smuzhiyun u8 default_prio)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
304*4882a593Smuzhiyun char qpdp_pl[MLXSW_REG_QPDP_LEN];
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun mlxsw_reg_qpdp_pack(qpdp_pl, mlxsw_sp_port->local_port, default_prio);
307*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdp), qpdp_pl);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_dscp_map * map)311*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port *mlxsw_sp_port,
312*4882a593Smuzhiyun struct dcb_ieee_app_dscp_map *map)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
315*4882a593Smuzhiyun char qpdpm_pl[MLXSW_REG_QPDPM_LEN];
316*4882a593Smuzhiyun short int i;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun mlxsw_reg_qpdpm_pack(qpdpm_pl, mlxsw_sp_port->local_port);
319*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(map->map); ++i)
320*4882a593Smuzhiyun mlxsw_reg_qpdpm_dscp_pack(qpdpm_pl, i, map->map[i]);
321*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdpm), qpdpm_pl);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun static int
mlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_prio_map * map)325*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port *mlxsw_sp_port,
326*4882a593Smuzhiyun struct dcb_ieee_app_prio_map *map)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
329*4882a593Smuzhiyun char qpdsm_pl[MLXSW_REG_QPDSM_LEN];
330*4882a593Smuzhiyun short int i;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun mlxsw_reg_qpdsm_pack(qpdsm_pl, mlxsw_sp_port->local_port);
333*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(map->map); ++i)
334*4882a593Smuzhiyun mlxsw_reg_qpdsm_prio_pack(qpdsm_pl, i, map->map[i]);
335*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdsm), qpdsm_pl);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port * mlxsw_sp_port)338*4882a593Smuzhiyun static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct dcb_ieee_app_prio_map prio_map;
341*4882a593Smuzhiyun struct dcb_ieee_app_dscp_map dscp_map;
342*4882a593Smuzhiyun u8 default_prio;
343*4882a593Smuzhiyun bool have_dscp;
344*4882a593Smuzhiyun int err;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun default_prio = mlxsw_sp_port_dcb_app_default_prio(mlxsw_sp_port);
347*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update_qpdp(mlxsw_sp_port, default_prio);
348*4882a593Smuzhiyun if (err) {
349*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Couldn't configure port default priority\n");
350*4882a593Smuzhiyun return err;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
354*4882a593Smuzhiyun &prio_map);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
357*4882a593Smuzhiyun &dscp_map);
358*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
359*4882a593Smuzhiyun &dscp_map);
360*4882a593Smuzhiyun if (err) {
361*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Couldn't configure priority map\n");
362*4882a593Smuzhiyun return err;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update_qpdsm(mlxsw_sp_port,
366*4882a593Smuzhiyun &prio_map);
367*4882a593Smuzhiyun if (err) {
368*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Couldn't configure DSCP rewrite map\n");
369*4882a593Smuzhiyun return err;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (!have_dscp) {
373*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
374*4882a593Smuzhiyun MLXSW_REG_QPTS_TRUST_STATE_PCP);
375*4882a593Smuzhiyun if (err)
376*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
377*4882a593Smuzhiyun return err;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
381*4882a593Smuzhiyun MLXSW_REG_QPTS_TRUST_STATE_DSCP);
382*4882a593Smuzhiyun if (err) {
383*4882a593Smuzhiyun /* A failure to set trust DSCP means that the QPDPM and QPDSM
384*4882a593Smuzhiyun * maps installed above are not in effect. And since we are here
385*4882a593Smuzhiyun * attempting to set trust DSCP, we couldn't have attempted to
386*4882a593Smuzhiyun * switch trust to PCP. Thus no cleanup is necessary.
387*4882a593Smuzhiyun */
388*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L3\n");
389*4882a593Smuzhiyun return err;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun return 0;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_setapp(struct net_device * dev,struct dcb_app * app)395*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_setapp(struct net_device *dev,
396*4882a593Smuzhiyun struct dcb_app *app)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
399*4882a593Smuzhiyun int err;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun err = mlxsw_sp_dcbnl_app_validate(dev, app);
402*4882a593Smuzhiyun if (err)
403*4882a593Smuzhiyun return err;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun err = dcb_ieee_setapp(dev, app);
406*4882a593Smuzhiyun if (err)
407*4882a593Smuzhiyun return err;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
410*4882a593Smuzhiyun if (err)
411*4882a593Smuzhiyun goto err_update;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return 0;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun err_update:
416*4882a593Smuzhiyun dcb_ieee_delapp(dev, app);
417*4882a593Smuzhiyun return err;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_delapp(struct net_device * dev,struct dcb_app * app)420*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_delapp(struct net_device *dev,
421*4882a593Smuzhiyun struct dcb_app *app)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
424*4882a593Smuzhiyun int err;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun err = dcb_ieee_delapp(dev, app);
427*4882a593Smuzhiyun if (err)
428*4882a593Smuzhiyun return err;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
431*4882a593Smuzhiyun if (err)
432*4882a593Smuzhiyun netdev_err(dev, "Failed to update DCB APP configuration\n");
433*4882a593Smuzhiyun return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)436*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device *dev,
437*4882a593Smuzhiyun struct ieee_maxrate *maxrate)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun memcpy(maxrate, mlxsw_sp_port->dcb.maxrate, sizeof(*maxrate));
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)446*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device *dev,
447*4882a593Smuzhiyun struct ieee_maxrate *maxrate)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
450*4882a593Smuzhiyun struct ieee_maxrate *my_maxrate = mlxsw_sp_port->dcb.maxrate;
451*4882a593Smuzhiyun int err, i;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
454*4882a593Smuzhiyun err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
455*4882a593Smuzhiyun MLXSW_REG_QEEC_HR_SUBGROUP,
456*4882a593Smuzhiyun i, 0,
457*4882a593Smuzhiyun maxrate->tc_maxrate[i], 0);
458*4882a593Smuzhiyun if (err) {
459*4882a593Smuzhiyun netdev_err(dev, "Failed to set maxrate for TC %d\n", i);
460*4882a593Smuzhiyun goto err_port_ets_maxrate_set;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun memcpy(mlxsw_sp_port->dcb.maxrate, maxrate, sizeof(*maxrate));
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun return 0;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun err_port_ets_maxrate_set:
469*4882a593Smuzhiyun for (i--; i >= 0; i--)
470*4882a593Smuzhiyun mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
471*4882a593Smuzhiyun MLXSW_REG_QEEC_HR_SUBGROUP,
472*4882a593Smuzhiyun i, 0,
473*4882a593Smuzhiyun my_maxrate->tc_maxrate[i], 0);
474*4882a593Smuzhiyun return err;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port * mlxsw_sp_port,u8 prio)477*4882a593Smuzhiyun static int mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port *mlxsw_sp_port,
478*4882a593Smuzhiyun u8 prio)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
481*4882a593Smuzhiyun struct ieee_pfc *my_pfc = mlxsw_sp_port->dcb.pfc;
482*4882a593Smuzhiyun char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
483*4882a593Smuzhiyun int err;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port,
486*4882a593Smuzhiyun MLXSW_REG_PPCNT_PRIO_CNT, prio);
487*4882a593Smuzhiyun err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
488*4882a593Smuzhiyun if (err)
489*4882a593Smuzhiyun return err;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun my_pfc->requests[prio] = mlxsw_reg_ppcnt_tx_pause_get(ppcnt_pl);
492*4882a593Smuzhiyun my_pfc->indications[prio] = mlxsw_reg_ppcnt_rx_pause_get(ppcnt_pl);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun return 0;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_getpfc(struct net_device * dev,struct ieee_pfc * pfc)497*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_getpfc(struct net_device *dev,
498*4882a593Smuzhiyun struct ieee_pfc *pfc)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
501*4882a593Smuzhiyun int err, i;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
504*4882a593Smuzhiyun err = mlxsw_sp_port_pfc_cnt_get(mlxsw_sp_port, i);
505*4882a593Smuzhiyun if (err) {
506*4882a593Smuzhiyun netdev_err(dev, "Failed to get PFC count for priority %d\n",
507*4882a593Smuzhiyun i);
508*4882a593Smuzhiyun return err;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun memcpy(pfc, mlxsw_sp_port->dcb.pfc, sizeof(*pfc));
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun return 0;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
mlxsw_sp_port_pfc_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_pfc * pfc)517*4882a593Smuzhiyun static int mlxsw_sp_port_pfc_set(struct mlxsw_sp_port *mlxsw_sp_port,
518*4882a593Smuzhiyun struct ieee_pfc *pfc)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun char pfcc_pl[MLXSW_REG_PFCC_LEN];
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
523*4882a593Smuzhiyun mlxsw_reg_pfcc_pprx_set(pfcc_pl, mlxsw_sp_port->link.rx_pause);
524*4882a593Smuzhiyun mlxsw_reg_pfcc_pptx_set(pfcc_pl, mlxsw_sp_port->link.tx_pause);
525*4882a593Smuzhiyun mlxsw_reg_pfcc_prio_pack(pfcc_pl, pfc->pfc_en);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
528*4882a593Smuzhiyun pfcc_pl);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
mlxsw_sp_dcbnl_ieee_setpfc(struct net_device * dev,struct ieee_pfc * pfc)531*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev,
532*4882a593Smuzhiyun struct ieee_pfc *pfc)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
535*4882a593Smuzhiyun bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
536*4882a593Smuzhiyun struct mlxsw_sp_hdroom orig_hdroom;
537*4882a593Smuzhiyun struct mlxsw_sp_hdroom hdroom;
538*4882a593Smuzhiyun int prio;
539*4882a593Smuzhiyun int err;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun if (pause_en && pfc->pfc_en) {
542*4882a593Smuzhiyun netdev_err(dev, "PAUSE frames already enabled on port\n");
543*4882a593Smuzhiyun return -EINVAL;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun orig_hdroom = *mlxsw_sp_port->hdroom;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun hdroom = orig_hdroom;
549*4882a593Smuzhiyun if (pfc->pfc_en)
550*4882a593Smuzhiyun hdroom.delay_bytes = DIV_ROUND_UP(pfc->delay, BITS_PER_BYTE);
551*4882a593Smuzhiyun else
552*4882a593Smuzhiyun hdroom.delay_bytes = 0;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
555*4882a593Smuzhiyun hdroom.prios.prio[prio].lossy = !(pfc->pfc_en & BIT(prio));
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
558*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
561*4882a593Smuzhiyun if (err) {
562*4882a593Smuzhiyun netdev_err(dev, "Failed to configure port's headroom for PFC\n");
563*4882a593Smuzhiyun return err;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun err = mlxsw_sp_port_pfc_set(mlxsw_sp_port, pfc);
567*4882a593Smuzhiyun if (err) {
568*4882a593Smuzhiyun netdev_err(dev, "Failed to configure PFC\n");
569*4882a593Smuzhiyun goto err_port_pfc_set;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun memcpy(mlxsw_sp_port->dcb.pfc, pfc, sizeof(*pfc));
573*4882a593Smuzhiyun mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun return 0;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun err_port_pfc_set:
578*4882a593Smuzhiyun mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
579*4882a593Smuzhiyun return err;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
mlxsw_sp_dcbnl_getbuffer(struct net_device * dev,struct dcbnl_buffer * buf)582*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
585*4882a593Smuzhiyun struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom;
586*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
587*4882a593Smuzhiyun int prio;
588*4882a593Smuzhiyun int i;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun buf->total_size = 0;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
593*4882a593Smuzhiyun for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
594*4882a593Smuzhiyun u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun if (i < DCBX_MAX_BUFFERS)
597*4882a593Smuzhiyun buf->buffer_size[i] = bytes;
598*4882a593Smuzhiyun buf->total_size += bytes;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
604*4882a593Smuzhiyun buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
mlxsw_sp_dcbnl_setbuffer(struct net_device * dev,struct dcbnl_buffer * buf)609*4882a593Smuzhiyun static int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
612*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
613*4882a593Smuzhiyun struct mlxsw_sp_hdroom hdroom;
614*4882a593Smuzhiyun int prio;
615*4882a593Smuzhiyun int i;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun hdroom = *mlxsw_sp_port->hdroom;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) {
620*4882a593Smuzhiyun netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n");
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
625*4882a593Smuzhiyun hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio];
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
628*4882a593Smuzhiyun for (i = 0; i < DCBX_MAX_BUFFERS; i++)
629*4882a593Smuzhiyun hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp,
630*4882a593Smuzhiyun buf->buffer_size[i]);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
633*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
634*4882a593Smuzhiyun mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
635*4882a593Smuzhiyun return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
639*4882a593Smuzhiyun .ieee_getets = mlxsw_sp_dcbnl_ieee_getets,
640*4882a593Smuzhiyun .ieee_setets = mlxsw_sp_dcbnl_ieee_setets,
641*4882a593Smuzhiyun .ieee_getmaxrate = mlxsw_sp_dcbnl_ieee_getmaxrate,
642*4882a593Smuzhiyun .ieee_setmaxrate = mlxsw_sp_dcbnl_ieee_setmaxrate,
643*4882a593Smuzhiyun .ieee_getpfc = mlxsw_sp_dcbnl_ieee_getpfc,
644*4882a593Smuzhiyun .ieee_setpfc = mlxsw_sp_dcbnl_ieee_setpfc,
645*4882a593Smuzhiyun .ieee_setapp = mlxsw_sp_dcbnl_ieee_setapp,
646*4882a593Smuzhiyun .ieee_delapp = mlxsw_sp_dcbnl_ieee_delapp,
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun .getdcbx = mlxsw_sp_dcbnl_getdcbx,
649*4882a593Smuzhiyun .setdcbx = mlxsw_sp_dcbnl_setdcbx,
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun .dcbnl_getbuffer = mlxsw_sp_dcbnl_getbuffer,
652*4882a593Smuzhiyun .dcbnl_setbuffer = mlxsw_sp_dcbnl_setbuffer,
653*4882a593Smuzhiyun };
654*4882a593Smuzhiyun
mlxsw_sp_port_ets_init(struct mlxsw_sp_port * mlxsw_sp_port)655*4882a593Smuzhiyun static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun mlxsw_sp_port->dcb.ets = kzalloc(sizeof(*mlxsw_sp_port->dcb.ets),
658*4882a593Smuzhiyun GFP_KERNEL);
659*4882a593Smuzhiyun if (!mlxsw_sp_port->dcb.ets)
660*4882a593Smuzhiyun return -ENOMEM;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun return 0;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
mlxsw_sp_port_ets_fini(struct mlxsw_sp_port * mlxsw_sp_port)667*4882a593Smuzhiyun static void mlxsw_sp_port_ets_fini(struct mlxsw_sp_port *mlxsw_sp_port)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun kfree(mlxsw_sp_port->dcb.ets);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port * mlxsw_sp_port)672*4882a593Smuzhiyun static int mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port *mlxsw_sp_port)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun int i;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun mlxsw_sp_port->dcb.maxrate = kmalloc(sizeof(*mlxsw_sp_port->dcb.maxrate),
677*4882a593Smuzhiyun GFP_KERNEL);
678*4882a593Smuzhiyun if (!mlxsw_sp_port->dcb.maxrate)
679*4882a593Smuzhiyun return -ENOMEM;
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
682*4882a593Smuzhiyun mlxsw_sp_port->dcb.maxrate->tc_maxrate[i] = MLXSW_REG_QEEC_MAS_DIS;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port * mlxsw_sp_port)687*4882a593Smuzhiyun static void mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port *mlxsw_sp_port)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun kfree(mlxsw_sp_port->dcb.maxrate);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
mlxsw_sp_port_pfc_init(struct mlxsw_sp_port * mlxsw_sp_port)692*4882a593Smuzhiyun static int mlxsw_sp_port_pfc_init(struct mlxsw_sp_port *mlxsw_sp_port)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun mlxsw_sp_port->dcb.pfc = kzalloc(sizeof(*mlxsw_sp_port->dcb.pfc),
695*4882a593Smuzhiyun GFP_KERNEL);
696*4882a593Smuzhiyun if (!mlxsw_sp_port->dcb.pfc)
697*4882a593Smuzhiyun return -ENOMEM;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun return 0;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun
mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port * mlxsw_sp_port)704*4882a593Smuzhiyun static void mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun kfree(mlxsw_sp_port->dcb.pfc);
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
mlxsw_sp_port_dcb_init(struct mlxsw_sp_port * mlxsw_sp_port)709*4882a593Smuzhiyun int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun int err;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
714*4882a593Smuzhiyun if (err)
715*4882a593Smuzhiyun return err;
716*4882a593Smuzhiyun err = mlxsw_sp_port_maxrate_init(mlxsw_sp_port);
717*4882a593Smuzhiyun if (err)
718*4882a593Smuzhiyun goto err_port_maxrate_init;
719*4882a593Smuzhiyun err = mlxsw_sp_port_pfc_init(mlxsw_sp_port);
720*4882a593Smuzhiyun if (err)
721*4882a593Smuzhiyun goto err_port_pfc_init;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun mlxsw_sp_port->dcb.trust_state = MLXSW_REG_QPTS_TRUST_STATE_PCP;
724*4882a593Smuzhiyun mlxsw_sp_port->dev->dcbnl_ops = &mlxsw_sp_dcbnl_ops;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun return 0;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun err_port_pfc_init:
729*4882a593Smuzhiyun mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
730*4882a593Smuzhiyun err_port_maxrate_init:
731*4882a593Smuzhiyun mlxsw_sp_port_ets_fini(mlxsw_sp_port);
732*4882a593Smuzhiyun return err;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port * mlxsw_sp_port)735*4882a593Smuzhiyun void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun mlxsw_sp_port_pfc_fini(mlxsw_sp_port);
738*4882a593Smuzhiyun mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
739*4882a593Smuzhiyun mlxsw_sp_port_ets_fini(mlxsw_sp_port);
740*4882a593Smuzhiyun }
741