19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29948a064SJiri Pirko /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3f00817dfSIdo Schimmel
4f00817dfSIdo Schimmel #include <linux/netdevice.h>
58e8dfe9fSIdo Schimmel #include <linux/string.h>
6d81a6bdbSIdo Schimmel #include <linux/bitops.h>
7f00817dfSIdo Schimmel #include <net/dcbnl.h>
8f00817dfSIdo Schimmel
9f00817dfSIdo Schimmel #include "spectrum.h"
108e8dfe9fSIdo Schimmel #include "reg.h"
11f00817dfSIdo Schimmel
mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused * dev)12f00817dfSIdo Schimmel static u8 mlxsw_sp_dcbnl_getdcbx(struct net_device __always_unused *dev)
13f00817dfSIdo Schimmel {
14f00817dfSIdo Schimmel return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
15f00817dfSIdo Schimmel }
16f00817dfSIdo Schimmel
mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused * dev,u8 mode)17f00817dfSIdo Schimmel static u8 mlxsw_sp_dcbnl_setdcbx(struct net_device __always_unused *dev,
18f00817dfSIdo Schimmel u8 mode)
19f00817dfSIdo Schimmel {
20f00817dfSIdo Schimmel return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
21f00817dfSIdo Schimmel }
22f00817dfSIdo Schimmel
mlxsw_sp_dcbnl_ieee_getets(struct net_device * dev,struct ieee_ets * ets)238e8dfe9fSIdo Schimmel static int mlxsw_sp_dcbnl_ieee_getets(struct net_device *dev,
248e8dfe9fSIdo Schimmel struct ieee_ets *ets)
258e8dfe9fSIdo Schimmel {
268e8dfe9fSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
278e8dfe9fSIdo Schimmel
288e8dfe9fSIdo Schimmel memcpy(ets, mlxsw_sp_port->dcb.ets, sizeof(*ets));
298e8dfe9fSIdo Schimmel
308e8dfe9fSIdo Schimmel return 0;
318e8dfe9fSIdo Schimmel }
328e8dfe9fSIdo Schimmel
mlxsw_sp_port_ets_validate(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)338e8dfe9fSIdo Schimmel static int mlxsw_sp_port_ets_validate(struct mlxsw_sp_port *mlxsw_sp_port,
348e8dfe9fSIdo Schimmel struct ieee_ets *ets)
358e8dfe9fSIdo Schimmel {
368e8dfe9fSIdo Schimmel struct net_device *dev = mlxsw_sp_port->dev;
378e8dfe9fSIdo Schimmel bool has_ets_tc = false;
388e8dfe9fSIdo Schimmel int i, tx_bw_sum = 0;
398e8dfe9fSIdo Schimmel
408e8dfe9fSIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
418e8dfe9fSIdo Schimmel switch (ets->tc_tsa[i]) {
428e8dfe9fSIdo Schimmel case IEEE_8021QAZ_TSA_STRICT:
438e8dfe9fSIdo Schimmel break;
448e8dfe9fSIdo Schimmel case IEEE_8021QAZ_TSA_ETS:
458e8dfe9fSIdo Schimmel has_ets_tc = true;
468e8dfe9fSIdo Schimmel tx_bw_sum += ets->tc_tx_bw[i];
478e8dfe9fSIdo Schimmel break;
488e8dfe9fSIdo Schimmel default:
498e8dfe9fSIdo Schimmel netdev_err(dev, "Only strict priority and ETS are supported\n");
508e8dfe9fSIdo Schimmel return -EINVAL;
518e8dfe9fSIdo Schimmel }
528e8dfe9fSIdo Schimmel
538e8dfe9fSIdo Schimmel if (ets->prio_tc[i] >= IEEE_8021QAZ_MAX_TCS) {
548e8dfe9fSIdo Schimmel netdev_err(dev, "Invalid TC\n");
558e8dfe9fSIdo Schimmel return -EINVAL;
568e8dfe9fSIdo Schimmel }
578e8dfe9fSIdo Schimmel }
588e8dfe9fSIdo Schimmel
598e8dfe9fSIdo Schimmel if (has_ets_tc && tx_bw_sum != 100) {
608e8dfe9fSIdo Schimmel netdev_err(dev, "Total ETS bandwidth should equal 100\n");
618e8dfe9fSIdo Schimmel return -EINVAL;
628e8dfe9fSIdo Schimmel }
638e8dfe9fSIdo Schimmel
648e8dfe9fSIdo Schimmel return 0;
658e8dfe9fSIdo Schimmel }
668e8dfe9fSIdo Schimmel
mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)67a2af44b6SAmit Cohen static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
688e8dfe9fSIdo Schimmel struct ieee_ets *ets)
698e8dfe9fSIdo Schimmel {
708e8dfe9fSIdo Schimmel struct net_device *dev = mlxsw_sp_port->dev;
715df825edSPetr Machata struct mlxsw_sp_hdroom hdroom;
725df825edSPetr Machata int prio;
738e8dfe9fSIdo Schimmel int err;
748e8dfe9fSIdo Schimmel
757ace2c36SPetr Machata hdroom = *mlxsw_sp_port->hdroom;
765df825edSPetr Machata for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
775df825edSPetr Machata hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio];
785df825edSPetr Machata mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
79ca21e84eSPetr Machata mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
802d9f703fSPetr Machata mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
815df825edSPetr Machata
827ace2c36SPetr Machata err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
838e8dfe9fSIdo Schimmel if (err) {
848e8dfe9fSIdo Schimmel netdev_err(dev, "Failed to configure port's headroom\n");
858e8dfe9fSIdo Schimmel return err;
868e8dfe9fSIdo Schimmel }
878e8dfe9fSIdo Schimmel
888e8dfe9fSIdo Schimmel return 0;
898e8dfe9fSIdo Schimmel }
908e8dfe9fSIdo Schimmel
__mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_ets * ets)918e8dfe9fSIdo Schimmel static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port,
928e8dfe9fSIdo Schimmel struct ieee_ets *ets)
938e8dfe9fSIdo Schimmel {
948e8dfe9fSIdo Schimmel struct ieee_ets *my_ets = mlxsw_sp_port->dcb.ets;
958e8dfe9fSIdo Schimmel struct net_device *dev = mlxsw_sp_port->dev;
968e8dfe9fSIdo Schimmel int i, err;
978e8dfe9fSIdo Schimmel
988e8dfe9fSIdo Schimmel /* Egress configuration. */
998e8dfe9fSIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1008e8dfe9fSIdo Schimmel bool dwrr = ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
1018e8dfe9fSIdo Schimmel u8 weight = ets->tc_tx_bw[i];
1028e8dfe9fSIdo Schimmel
1038e8dfe9fSIdo Schimmel err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
1049cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP, i,
1058e8dfe9fSIdo Schimmel 0, dwrr, weight);
1068e8dfe9fSIdo Schimmel if (err) {
1078e8dfe9fSIdo Schimmel netdev_err(dev, "Failed to link subgroup ETS element %d to group\n",
1088e8dfe9fSIdo Schimmel i);
1098e8dfe9fSIdo Schimmel goto err_port_ets_set;
1108e8dfe9fSIdo Schimmel }
1118e8dfe9fSIdo Schimmel }
1128e8dfe9fSIdo Schimmel
1138e8dfe9fSIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
1148e8dfe9fSIdo Schimmel err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i,
1158e8dfe9fSIdo Schimmel ets->prio_tc[i]);
1168e8dfe9fSIdo Schimmel if (err) {
1178e8dfe9fSIdo Schimmel netdev_err(dev, "Failed to map prio %d to TC %d\n", i,
1188e8dfe9fSIdo Schimmel ets->prio_tc[i]);
1198e8dfe9fSIdo Schimmel goto err_port_prio_tc_set;
1208e8dfe9fSIdo Schimmel }
1218e8dfe9fSIdo Schimmel }
1228e8dfe9fSIdo Schimmel
1238e8dfe9fSIdo Schimmel /* Ingress configuration. */
124a2af44b6SAmit Cohen err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets);
1258e8dfe9fSIdo Schimmel if (err)
1268e8dfe9fSIdo Schimmel goto err_port_headroom_set;
1278e8dfe9fSIdo Schimmel
1288e8dfe9fSIdo Schimmel return 0;
1298e8dfe9fSIdo Schimmel
1308e8dfe9fSIdo Schimmel err_port_headroom_set:
1318e8dfe9fSIdo Schimmel i = IEEE_8021QAZ_MAX_TCS;
1328e8dfe9fSIdo Schimmel err_port_prio_tc_set:
1338e8dfe9fSIdo Schimmel for (i--; i >= 0; i--)
1348e8dfe9fSIdo Schimmel mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, my_ets->prio_tc[i]);
1358e8dfe9fSIdo Schimmel i = IEEE_8021QAZ_MAX_TCS;
1368e8dfe9fSIdo Schimmel err_port_ets_set:
1378e8dfe9fSIdo Schimmel for (i--; i >= 0; i--) {
1388e8dfe9fSIdo Schimmel bool dwrr = my_ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS;
1398e8dfe9fSIdo Schimmel u8 weight = my_ets->tc_tx_bw[i];
1408e8dfe9fSIdo Schimmel
1418e8dfe9fSIdo Schimmel err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
1429cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP, i,
1438e8dfe9fSIdo Schimmel 0, dwrr, weight);
1448e8dfe9fSIdo Schimmel }
1458e8dfe9fSIdo Schimmel return err;
1468e8dfe9fSIdo Schimmel }
1478e8dfe9fSIdo Schimmel
mlxsw_sp_dcbnl_ieee_setets(struct net_device * dev,struct ieee_ets * ets)1488e8dfe9fSIdo Schimmel static int mlxsw_sp_dcbnl_ieee_setets(struct net_device *dev,
1498e8dfe9fSIdo Schimmel struct ieee_ets *ets)
1508e8dfe9fSIdo Schimmel {
1518e8dfe9fSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1528e8dfe9fSIdo Schimmel int err;
1538e8dfe9fSIdo Schimmel
1548e8dfe9fSIdo Schimmel err = mlxsw_sp_port_ets_validate(mlxsw_sp_port, ets);
1558e8dfe9fSIdo Schimmel if (err)
1568e8dfe9fSIdo Schimmel return err;
1578e8dfe9fSIdo Schimmel
1588e8dfe9fSIdo Schimmel err = __mlxsw_sp_dcbnl_ieee_setets(mlxsw_sp_port, ets);
1598e8dfe9fSIdo Schimmel if (err)
1608e8dfe9fSIdo Schimmel return err;
1618e8dfe9fSIdo Schimmel
1628e8dfe9fSIdo Schimmel memcpy(mlxsw_sp_port->dcb.ets, ets, sizeof(*ets));
16328f5275eSIdo Schimmel mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
1648e8dfe9fSIdo Schimmel
1658e8dfe9fSIdo Schimmel return 0;
1668e8dfe9fSIdo Schimmel }
1678e8dfe9fSIdo Schimmel
mlxsw_sp_dcbnl_app_validate(struct net_device * dev,struct dcb_app * app)168b2b1dab6SPetr Machata static int mlxsw_sp_dcbnl_app_validate(struct net_device *dev,
169b2b1dab6SPetr Machata struct dcb_app *app)
170b2b1dab6SPetr Machata {
171b2b1dab6SPetr Machata if (app->priority >= IEEE_8021QAZ_MAX_TCS) {
172b2b1dab6SPetr Machata netdev_err(dev, "APP entry with priority value %u is invalid\n",
173b2b1dab6SPetr Machata app->priority);
174b2b1dab6SPetr Machata return -EINVAL;
175b2b1dab6SPetr Machata }
176b2b1dab6SPetr Machata
177b2b1dab6SPetr Machata switch (app->selector) {
178b2b1dab6SPetr Machata case IEEE_8021QAZ_APP_SEL_DSCP:
179b2b1dab6SPetr Machata if (app->protocol >= 64) {
180b2b1dab6SPetr Machata netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n",
181b2b1dab6SPetr Machata app->protocol);
182b2b1dab6SPetr Machata return -EINVAL;
183b2b1dab6SPetr Machata }
184b2b1dab6SPetr Machata break;
185b2b1dab6SPetr Machata
186b2b1dab6SPetr Machata case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
187b2b1dab6SPetr Machata if (app->protocol) {
188b2b1dab6SPetr Machata netdev_err(dev, "EtherType APP entries with protocol value != 0 not supported\n");
189b2b1dab6SPetr Machata return -EINVAL;
190b2b1dab6SPetr Machata }
191b2b1dab6SPetr Machata break;
192b2b1dab6SPetr Machata
193b2b1dab6SPetr Machata default:
194b2b1dab6SPetr Machata netdev_err(dev, "APP entries with selector %u not supported\n",
195b2b1dab6SPetr Machata app->selector);
196b2b1dab6SPetr Machata return -EINVAL;
197b2b1dab6SPetr Machata }
198b2b1dab6SPetr Machata
199b2b1dab6SPetr Machata return 0;
200b2b1dab6SPetr Machata }
201b2b1dab6SPetr Machata
202b2b1dab6SPetr Machata static u8
mlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port * mlxsw_sp_port)203b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_default_prio(struct mlxsw_sp_port *mlxsw_sp_port)
204b2b1dab6SPetr Machata {
205b2b1dab6SPetr Machata u8 prio_mask;
206b2b1dab6SPetr Machata
207b2b1dab6SPetr Machata prio_mask = dcb_ieee_getapp_default_prio_mask(mlxsw_sp_port->dev);
208b2b1dab6SPetr Machata if (prio_mask)
209b2b1dab6SPetr Machata /* Take the highest configured priority. */
210b2b1dab6SPetr Machata return fls(prio_mask) - 1;
211b2b1dab6SPetr Machata
212b2b1dab6SPetr Machata return 0;
213b2b1dab6SPetr Machata }
214b2b1dab6SPetr Machata
215b2b1dab6SPetr Machata 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)216b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_dscp_prio_map(struct mlxsw_sp_port *mlxsw_sp_port,
217b2b1dab6SPetr Machata u8 default_prio,
218b2b1dab6SPetr Machata struct dcb_ieee_app_dscp_map *map)
219b2b1dab6SPetr Machata {
220b2b1dab6SPetr Machata int i;
221b2b1dab6SPetr Machata
222b2b1dab6SPetr Machata dcb_ieee_getapp_dscp_prio_mask_map(mlxsw_sp_port->dev, map);
223b2b1dab6SPetr Machata for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
224b2b1dab6SPetr Machata if (map->map[i])
225b2b1dab6SPetr Machata map->map[i] = fls(map->map[i]) - 1;
226b2b1dab6SPetr Machata else
227b2b1dab6SPetr Machata map->map[i] = default_prio;
228b2b1dab6SPetr Machata }
229b2b1dab6SPetr Machata }
230b2b1dab6SPetr Machata
231b2b1dab6SPetr Machata static bool
mlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_prio_map * map)232b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_prio_dscp_map(struct mlxsw_sp_port *mlxsw_sp_port,
233b2b1dab6SPetr Machata struct dcb_ieee_app_prio_map *map)
234b2b1dab6SPetr Machata {
235b2b1dab6SPetr Machata bool have_dscp = false;
236b2b1dab6SPetr Machata int i;
237b2b1dab6SPetr Machata
238b2b1dab6SPetr Machata dcb_ieee_getapp_prio_dscp_mask_map(mlxsw_sp_port->dev, map);
239b2b1dab6SPetr Machata for (i = 0; i < ARRAY_SIZE(map->map); ++i) {
240b2b1dab6SPetr Machata if (map->map[i]) {
241b2b1dab6SPetr Machata map->map[i] = fls64(map->map[i]) - 1;
242b2b1dab6SPetr Machata have_dscp = true;
243b2b1dab6SPetr Machata }
244b2b1dab6SPetr Machata }
245b2b1dab6SPetr Machata
246b2b1dab6SPetr Machata return have_dscp;
247b2b1dab6SPetr Machata }
248b2b1dab6SPetr Machata
249b2b1dab6SPetr Machata static int
mlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qpts_trust_state ts)250b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_update_qpts(struct mlxsw_sp_port *mlxsw_sp_port,
251b2b1dab6SPetr Machata enum mlxsw_reg_qpts_trust_state ts)
252b2b1dab6SPetr Machata {
253b2b1dab6SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
254b2b1dab6SPetr Machata char qpts_pl[MLXSW_REG_QPTS_LEN];
255b2b1dab6SPetr Machata
256b2b1dab6SPetr Machata mlxsw_reg_qpts_pack(qpts_pl, mlxsw_sp_port->local_port, ts);
257b2b1dab6SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpts), qpts_pl);
258b2b1dab6SPetr Machata }
259b2b1dab6SPetr Machata
260b2b1dab6SPetr Machata static int
mlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port * mlxsw_sp_port,bool rewrite_dscp)261b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_update_qrwe(struct mlxsw_sp_port *mlxsw_sp_port,
262b2b1dab6SPetr Machata bool rewrite_dscp)
263b2b1dab6SPetr Machata {
264b2b1dab6SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
265b2b1dab6SPetr Machata char qrwe_pl[MLXSW_REG_QRWE_LEN];
266b2b1dab6SPetr Machata
267b2b1dab6SPetr Machata mlxsw_reg_qrwe_pack(qrwe_pl, mlxsw_sp_port->local_port,
268b2b1dab6SPetr Machata false, rewrite_dscp);
269b2b1dab6SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qrwe), qrwe_pl);
270b2b1dab6SPetr Machata }
271b2b1dab6SPetr Machata
272b2b1dab6SPetr Machata static int
mlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qpts_trust_state ts)273b2b1dab6SPetr Machata mlxsw_sp_port_dcb_toggle_trust(struct mlxsw_sp_port *mlxsw_sp_port,
274b2b1dab6SPetr Machata enum mlxsw_reg_qpts_trust_state ts)
275b2b1dab6SPetr Machata {
276b2b1dab6SPetr Machata bool rewrite_dscp = ts == MLXSW_REG_QPTS_TRUST_STATE_DSCP;
277b2b1dab6SPetr Machata int err;
278b2b1dab6SPetr Machata
279b2b1dab6SPetr Machata if (mlxsw_sp_port->dcb.trust_state == ts)
280b2b1dab6SPetr Machata return 0;
281b2b1dab6SPetr Machata
282b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port, ts);
283b2b1dab6SPetr Machata if (err)
284b2b1dab6SPetr Machata return err;
285b2b1dab6SPetr Machata
286b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update_qrwe(mlxsw_sp_port, rewrite_dscp);
287b2b1dab6SPetr Machata if (err)
288b2b1dab6SPetr Machata goto err_update_qrwe;
289b2b1dab6SPetr Machata
290b2b1dab6SPetr Machata mlxsw_sp_port->dcb.trust_state = ts;
291b2b1dab6SPetr Machata return 0;
292b2b1dab6SPetr Machata
293b2b1dab6SPetr Machata err_update_qrwe:
294b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_update_qpts(mlxsw_sp_port,
295b2b1dab6SPetr Machata mlxsw_sp_port->dcb.trust_state);
296b2b1dab6SPetr Machata return err;
297b2b1dab6SPetr Machata }
298b2b1dab6SPetr Machata
299b2b1dab6SPetr Machata static int
mlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port * mlxsw_sp_port,u8 default_prio)300379a00ddSPetr Machata mlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port *mlxsw_sp_port,
301379a00ddSPetr Machata u8 default_prio)
302379a00ddSPetr Machata {
303379a00ddSPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
304379a00ddSPetr Machata char qpdp_pl[MLXSW_REG_QPDP_LEN];
305379a00ddSPetr Machata
306379a00ddSPetr Machata mlxsw_reg_qpdp_pack(qpdp_pl, mlxsw_sp_port->local_port, default_prio);
307379a00ddSPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdp), qpdp_pl);
308379a00ddSPetr Machata }
309379a00ddSPetr Machata
310379a00ddSPetr Machata static int
mlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_dscp_map * map)311b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port *mlxsw_sp_port,
312b2b1dab6SPetr Machata struct dcb_ieee_app_dscp_map *map)
313b2b1dab6SPetr Machata {
314b2b1dab6SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
315b2b1dab6SPetr Machata char qpdpm_pl[MLXSW_REG_QPDPM_LEN];
316b2b1dab6SPetr Machata short int i;
317b2b1dab6SPetr Machata
318b2b1dab6SPetr Machata mlxsw_reg_qpdpm_pack(qpdpm_pl, mlxsw_sp_port->local_port);
319b2b1dab6SPetr Machata for (i = 0; i < ARRAY_SIZE(map->map); ++i)
320b2b1dab6SPetr Machata mlxsw_reg_qpdpm_dscp_pack(qpdpm_pl, i, map->map[i]);
321b2b1dab6SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdpm), qpdpm_pl);
322b2b1dab6SPetr Machata }
323b2b1dab6SPetr Machata
324b2b1dab6SPetr Machata static int
mlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port * mlxsw_sp_port,struct dcb_ieee_app_prio_map * map)325b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_update_qpdsm(struct mlxsw_sp_port *mlxsw_sp_port,
326b2b1dab6SPetr Machata struct dcb_ieee_app_prio_map *map)
327b2b1dab6SPetr Machata {
328b2b1dab6SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
329b2b1dab6SPetr Machata char qpdsm_pl[MLXSW_REG_QPDSM_LEN];
330b2b1dab6SPetr Machata short int i;
331b2b1dab6SPetr Machata
332b2b1dab6SPetr Machata mlxsw_reg_qpdsm_pack(qpdsm_pl, mlxsw_sp_port->local_port);
333b2b1dab6SPetr Machata for (i = 0; i < ARRAY_SIZE(map->map); ++i)
334b2b1dab6SPetr Machata mlxsw_reg_qpdsm_prio_pack(qpdsm_pl, i, map->map[i]);
335b2b1dab6SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdsm), qpdsm_pl);
336b2b1dab6SPetr Machata }
337b2b1dab6SPetr Machata
mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port * mlxsw_sp_port)338b2b1dab6SPetr Machata static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
339b2b1dab6SPetr Machata {
340b2b1dab6SPetr Machata struct dcb_ieee_app_prio_map prio_map;
341b2b1dab6SPetr Machata struct dcb_ieee_app_dscp_map dscp_map;
342b2b1dab6SPetr Machata u8 default_prio;
343b2b1dab6SPetr Machata bool have_dscp;
344b2b1dab6SPetr Machata int err;
345b2b1dab6SPetr Machata
346b2b1dab6SPetr Machata default_prio = mlxsw_sp_port_dcb_app_default_prio(mlxsw_sp_port);
347379a00ddSPetr Machata err = mlxsw_sp_port_dcb_app_update_qpdp(mlxsw_sp_port, default_prio);
348379a00ddSPetr Machata if (err) {
349379a00ddSPetr Machata netdev_err(mlxsw_sp_port->dev, "Couldn't configure port default priority\n");
350379a00ddSPetr Machata return err;
351379a00ddSPetr Machata }
352379a00ddSPetr Machata
353b2b1dab6SPetr Machata have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
354b2b1dab6SPetr Machata &prio_map);
355b2b1dab6SPetr Machata
356b2b1dab6SPetr Machata mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
357b2b1dab6SPetr Machata &dscp_map);
358b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
359b2b1dab6SPetr Machata &dscp_map);
360b2b1dab6SPetr Machata if (err) {
361b2b1dab6SPetr Machata netdev_err(mlxsw_sp_port->dev, "Couldn't configure priority map\n");
362b2b1dab6SPetr Machata return err;
363b2b1dab6SPetr Machata }
364b2b1dab6SPetr Machata
365b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update_qpdsm(mlxsw_sp_port,
366b2b1dab6SPetr Machata &prio_map);
367b2b1dab6SPetr Machata if (err) {
368b2b1dab6SPetr Machata netdev_err(mlxsw_sp_port->dev, "Couldn't configure DSCP rewrite map\n");
369b2b1dab6SPetr Machata return err;
370b2b1dab6SPetr Machata }
371b2b1dab6SPetr Machata
372dedfde2fSPetr Machata if (!have_dscp) {
373dedfde2fSPetr Machata err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
374dedfde2fSPetr Machata MLXSW_REG_QPTS_TRUST_STATE_PCP);
375dedfde2fSPetr Machata if (err)
376dedfde2fSPetr Machata netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
377dedfde2fSPetr Machata return err;
378dedfde2fSPetr Machata }
379dedfde2fSPetr Machata
380b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
381b2b1dab6SPetr Machata MLXSW_REG_QPTS_TRUST_STATE_DSCP);
382b2b1dab6SPetr Machata if (err) {
383b2b1dab6SPetr Machata /* A failure to set trust DSCP means that the QPDPM and QPDSM
384b2b1dab6SPetr Machata * maps installed above are not in effect. And since we are here
385b2b1dab6SPetr Machata * attempting to set trust DSCP, we couldn't have attempted to
386b2b1dab6SPetr Machata * switch trust to PCP. Thus no cleanup is necessary.
387b2b1dab6SPetr Machata */
388b2b1dab6SPetr Machata netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L3\n");
389b2b1dab6SPetr Machata return err;
390b2b1dab6SPetr Machata }
391b2b1dab6SPetr Machata
392b2b1dab6SPetr Machata return 0;
393b2b1dab6SPetr Machata }
394b2b1dab6SPetr Machata
mlxsw_sp_dcbnl_ieee_setapp(struct net_device * dev,struct dcb_app * app)395b2b1dab6SPetr Machata static int mlxsw_sp_dcbnl_ieee_setapp(struct net_device *dev,
396b2b1dab6SPetr Machata struct dcb_app *app)
397b2b1dab6SPetr Machata {
398b2b1dab6SPetr Machata struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
399b2b1dab6SPetr Machata int err;
400b2b1dab6SPetr Machata
401b2b1dab6SPetr Machata err = mlxsw_sp_dcbnl_app_validate(dev, app);
402b2b1dab6SPetr Machata if (err)
403b2b1dab6SPetr Machata return err;
404b2b1dab6SPetr Machata
405b2b1dab6SPetr Machata err = dcb_ieee_setapp(dev, app);
406b2b1dab6SPetr Machata if (err)
407b2b1dab6SPetr Machata return err;
408b2b1dab6SPetr Machata
409b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
410b2b1dab6SPetr Machata if (err)
411b2b1dab6SPetr Machata goto err_update;
412b2b1dab6SPetr Machata
413b2b1dab6SPetr Machata return 0;
414b2b1dab6SPetr Machata
415b2b1dab6SPetr Machata err_update:
416b2b1dab6SPetr Machata dcb_ieee_delapp(dev, app);
417b2b1dab6SPetr Machata return err;
418b2b1dab6SPetr Machata }
419b2b1dab6SPetr Machata
mlxsw_sp_dcbnl_ieee_delapp(struct net_device * dev,struct dcb_app * app)420b2b1dab6SPetr Machata static int mlxsw_sp_dcbnl_ieee_delapp(struct net_device *dev,
421b2b1dab6SPetr Machata struct dcb_app *app)
422b2b1dab6SPetr Machata {
423b2b1dab6SPetr Machata struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
424b2b1dab6SPetr Machata int err;
425b2b1dab6SPetr Machata
426b2b1dab6SPetr Machata err = dcb_ieee_delapp(dev, app);
427b2b1dab6SPetr Machata if (err)
428b2b1dab6SPetr Machata return err;
429b2b1dab6SPetr Machata
430b2b1dab6SPetr Machata err = mlxsw_sp_port_dcb_app_update(mlxsw_sp_port);
431b2b1dab6SPetr Machata if (err)
432b2b1dab6SPetr Machata netdev_err(dev, "Failed to update DCB APP configuration\n");
433b2b1dab6SPetr Machata return 0;
434b2b1dab6SPetr Machata }
435b2b1dab6SPetr Machata
mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)436cc7cf517SIdo Schimmel static int mlxsw_sp_dcbnl_ieee_getmaxrate(struct net_device *dev,
437cc7cf517SIdo Schimmel struct ieee_maxrate *maxrate)
438cc7cf517SIdo Schimmel {
439cc7cf517SIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
440cc7cf517SIdo Schimmel
441cc7cf517SIdo Schimmel memcpy(maxrate, mlxsw_sp_port->dcb.maxrate, sizeof(*maxrate));
442cc7cf517SIdo Schimmel
443cc7cf517SIdo Schimmel return 0;
444cc7cf517SIdo Schimmel }
445cc7cf517SIdo Schimmel
mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device * dev,struct ieee_maxrate * maxrate)446cc7cf517SIdo Schimmel static int mlxsw_sp_dcbnl_ieee_setmaxrate(struct net_device *dev,
447cc7cf517SIdo Schimmel struct ieee_maxrate *maxrate)
448cc7cf517SIdo Schimmel {
449cc7cf517SIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
450cc7cf517SIdo Schimmel struct ieee_maxrate *my_maxrate = mlxsw_sp_port->dcb.maxrate;
451cc7cf517SIdo Schimmel int err, i;
452cc7cf517SIdo Schimmel
453cc7cf517SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
454cc7cf517SIdo Schimmel err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
4559cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP,
456cc7cf517SIdo Schimmel i, 0,
457dbacf8baSPetr Machata maxrate->tc_maxrate[i], 0);
458cc7cf517SIdo Schimmel if (err) {
459cc7cf517SIdo Schimmel netdev_err(dev, "Failed to set maxrate for TC %d\n", i);
460cc7cf517SIdo Schimmel goto err_port_ets_maxrate_set;
461cc7cf517SIdo Schimmel }
462cc7cf517SIdo Schimmel }
463cc7cf517SIdo Schimmel
464cc7cf517SIdo Schimmel memcpy(mlxsw_sp_port->dcb.maxrate, maxrate, sizeof(*maxrate));
465cc7cf517SIdo Schimmel
466cc7cf517SIdo Schimmel return 0;
467cc7cf517SIdo Schimmel
468cc7cf517SIdo Schimmel err_port_ets_maxrate_set:
469cc7cf517SIdo Schimmel for (i--; i >= 0; i--)
470cc7cf517SIdo Schimmel mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
4719cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP,
472dbacf8baSPetr Machata i, 0,
473dbacf8baSPetr Machata my_maxrate->tc_maxrate[i], 0);
474cc7cf517SIdo Schimmel return err;
475cc7cf517SIdo Schimmel }
476cc7cf517SIdo Schimmel
mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port * mlxsw_sp_port,u8 prio)477d81a6bdbSIdo Schimmel static int mlxsw_sp_port_pfc_cnt_get(struct mlxsw_sp_port *mlxsw_sp_port,
478d81a6bdbSIdo Schimmel u8 prio)
479d81a6bdbSIdo Schimmel {
480d81a6bdbSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
481d81a6bdbSIdo Schimmel struct ieee_pfc *my_pfc = mlxsw_sp_port->dcb.pfc;
482d81a6bdbSIdo Schimmel char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
483d81a6bdbSIdo Schimmel int err;
484d81a6bdbSIdo Schimmel
485d81a6bdbSIdo Schimmel mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port,
486d81a6bdbSIdo Schimmel MLXSW_REG_PPCNT_PRIO_CNT, prio);
487d81a6bdbSIdo Schimmel err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
488d81a6bdbSIdo Schimmel if (err)
489d81a6bdbSIdo Schimmel return err;
490d81a6bdbSIdo Schimmel
491d81a6bdbSIdo Schimmel my_pfc->requests[prio] = mlxsw_reg_ppcnt_tx_pause_get(ppcnt_pl);
492d81a6bdbSIdo Schimmel my_pfc->indications[prio] = mlxsw_reg_ppcnt_rx_pause_get(ppcnt_pl);
493d81a6bdbSIdo Schimmel
494d81a6bdbSIdo Schimmel return 0;
495d81a6bdbSIdo Schimmel }
496d81a6bdbSIdo Schimmel
mlxsw_sp_dcbnl_ieee_getpfc(struct net_device * dev,struct ieee_pfc * pfc)497d81a6bdbSIdo Schimmel static int mlxsw_sp_dcbnl_ieee_getpfc(struct net_device *dev,
498d81a6bdbSIdo Schimmel struct ieee_pfc *pfc)
499d81a6bdbSIdo Schimmel {
500d81a6bdbSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
501d81a6bdbSIdo Schimmel int err, i;
502d81a6bdbSIdo Schimmel
503d81a6bdbSIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
504d81a6bdbSIdo Schimmel err = mlxsw_sp_port_pfc_cnt_get(mlxsw_sp_port, i);
505d81a6bdbSIdo Schimmel if (err) {
506d81a6bdbSIdo Schimmel netdev_err(dev, "Failed to get PFC count for priority %d\n",
507d81a6bdbSIdo Schimmel i);
508d81a6bdbSIdo Schimmel return err;
509d81a6bdbSIdo Schimmel }
510d81a6bdbSIdo Schimmel }
511d81a6bdbSIdo Schimmel
512d81a6bdbSIdo Schimmel memcpy(pfc, mlxsw_sp_port->dcb.pfc, sizeof(*pfc));
513d81a6bdbSIdo Schimmel
514d81a6bdbSIdo Schimmel return 0;
515d81a6bdbSIdo Schimmel }
516d81a6bdbSIdo Schimmel
mlxsw_sp_port_pfc_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ieee_pfc * pfc)517d81a6bdbSIdo Schimmel static int mlxsw_sp_port_pfc_set(struct mlxsw_sp_port *mlxsw_sp_port,
518d81a6bdbSIdo Schimmel struct ieee_pfc *pfc)
519d81a6bdbSIdo Schimmel {
520d81a6bdbSIdo Schimmel char pfcc_pl[MLXSW_REG_PFCC_LEN];
521d81a6bdbSIdo Schimmel
522d81a6bdbSIdo Schimmel mlxsw_reg_pfcc_pack(pfcc_pl, mlxsw_sp_port->local_port);
52307d50caeSIdo Schimmel mlxsw_reg_pfcc_pprx_set(pfcc_pl, mlxsw_sp_port->link.rx_pause);
52407d50caeSIdo Schimmel mlxsw_reg_pfcc_pptx_set(pfcc_pl, mlxsw_sp_port->link.tx_pause);
525d81a6bdbSIdo Schimmel mlxsw_reg_pfcc_prio_pack(pfcc_pl, pfc->pfc_en);
526d81a6bdbSIdo Schimmel
527d81a6bdbSIdo Schimmel return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pfcc),
528d81a6bdbSIdo Schimmel pfcc_pl);
529d81a6bdbSIdo Schimmel }
530d81a6bdbSIdo Schimmel
mlxsw_sp_dcbnl_ieee_setpfc(struct net_device * dev,struct ieee_pfc * pfc)531d81a6bdbSIdo Schimmel static int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev,
532d81a6bdbSIdo Schimmel struct ieee_pfc *pfc)
533d81a6bdbSIdo Schimmel {
534d81a6bdbSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
535b489a200SIdo Schimmel bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
536b7e07bbdSPetr Machata struct mlxsw_sp_hdroom orig_hdroom;
537b7e07bbdSPetr Machata struct mlxsw_sp_hdroom hdroom;
538ca21e84eSPetr Machata int prio;
539d81a6bdbSIdo Schimmel int err;
540d81a6bdbSIdo Schimmel
541b489a200SIdo Schimmel if (pause_en && pfc->pfc_en) {
542d81a6bdbSIdo Schimmel netdev_err(dev, "PAUSE frames already enabled on port\n");
543d81a6bdbSIdo Schimmel return -EINVAL;
544d81a6bdbSIdo Schimmel }
545d81a6bdbSIdo Schimmel
546b7e07bbdSPetr Machata orig_hdroom = *mlxsw_sp_port->hdroom;
547b7e07bbdSPetr Machata
548b7e07bbdSPetr Machata hdroom = orig_hdroom;
549b7e07bbdSPetr Machata if (pfc->pfc_en)
550b7e07bbdSPetr Machata hdroom.delay_bytes = DIV_ROUND_UP(pfc->delay, BITS_PER_BYTE);
551b7e07bbdSPetr Machata else
552b7e07bbdSPetr Machata hdroom.delay_bytes = 0;
553b7e07bbdSPetr Machata
554ca21e84eSPetr Machata for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
555ca21e84eSPetr Machata hdroom.prios.prio[prio].lossy = !(pfc->pfc_en & BIT(prio));
556ca21e84eSPetr Machata
557ca21e84eSPetr Machata mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
5582d9f703fSPetr Machata mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
559ca21e84eSPetr Machata
5602d9f703fSPetr Machata err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
561d81a6bdbSIdo Schimmel if (err) {
562d81a6bdbSIdo Schimmel netdev_err(dev, "Failed to configure port's headroom for PFC\n");
563d81a6bdbSIdo Schimmel return err;
564d81a6bdbSIdo Schimmel }
565d81a6bdbSIdo Schimmel
566d81a6bdbSIdo Schimmel err = mlxsw_sp_port_pfc_set(mlxsw_sp_port, pfc);
567d81a6bdbSIdo Schimmel if (err) {
568d81a6bdbSIdo Schimmel netdev_err(dev, "Failed to configure PFC\n");
569d81a6bdbSIdo Schimmel goto err_port_pfc_set;
570d81a6bdbSIdo Schimmel }
571d81a6bdbSIdo Schimmel
572d81a6bdbSIdo Schimmel memcpy(mlxsw_sp_port->dcb.pfc, pfc, sizeof(*pfc));
57328f5275eSIdo Schimmel mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
574d81a6bdbSIdo Schimmel
575d81a6bdbSIdo Schimmel return 0;
576d81a6bdbSIdo Schimmel
577d81a6bdbSIdo Schimmel err_port_pfc_set:
5782d9f703fSPetr Machata mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
579d81a6bdbSIdo Schimmel return err;
580d81a6bdbSIdo Schimmel }
581d81a6bdbSIdo Schimmel
mlxsw_sp_dcbnl_getbuffer(struct net_device * dev,struct dcbnl_buffer * buf)582*5ebc6031SPetr Machata static int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
583*5ebc6031SPetr Machata {
584*5ebc6031SPetr Machata struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
585*5ebc6031SPetr Machata struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom;
586*5ebc6031SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
587*5ebc6031SPetr Machata int prio;
588*5ebc6031SPetr Machata int i;
589*5ebc6031SPetr Machata
590*5ebc6031SPetr Machata buf->total_size = 0;
591*5ebc6031SPetr Machata
592*5ebc6031SPetr Machata BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
593*5ebc6031SPetr Machata for (i = 0; i < MLXSW_SP_PB_COUNT; i++) {
594*5ebc6031SPetr Machata u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells);
595*5ebc6031SPetr Machata
596*5ebc6031SPetr Machata if (i < DCBX_MAX_BUFFERS)
597*5ebc6031SPetr Machata buf->buffer_size[i] = bytes;
598*5ebc6031SPetr Machata buf->total_size += bytes;
599*5ebc6031SPetr Machata }
600*5ebc6031SPetr Machata
601*5ebc6031SPetr Machata buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells);
602*5ebc6031SPetr Machata
603*5ebc6031SPetr Machata for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
604*5ebc6031SPetr Machata buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx;
605*5ebc6031SPetr Machata
606*5ebc6031SPetr Machata return 0;
607*5ebc6031SPetr Machata }
608*5ebc6031SPetr Machata
mlxsw_sp_dcbnl_setbuffer(struct net_device * dev,struct dcbnl_buffer * buf)609*5ebc6031SPetr Machata static int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf)
610*5ebc6031SPetr Machata {
611*5ebc6031SPetr Machata struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
612*5ebc6031SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
613*5ebc6031SPetr Machata struct mlxsw_sp_hdroom hdroom;
614*5ebc6031SPetr Machata int prio;
615*5ebc6031SPetr Machata int i;
616*5ebc6031SPetr Machata
617*5ebc6031SPetr Machata hdroom = *mlxsw_sp_port->hdroom;
618*5ebc6031SPetr Machata
619*5ebc6031SPetr Machata if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) {
620*5ebc6031SPetr Machata netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n");
621*5ebc6031SPetr Machata return -EINVAL;
622*5ebc6031SPetr Machata }
623*5ebc6031SPetr Machata
624*5ebc6031SPetr Machata for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++)
625*5ebc6031SPetr Machata hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio];
626*5ebc6031SPetr Machata
627*5ebc6031SPetr Machata BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT);
628*5ebc6031SPetr Machata for (i = 0; i < DCBX_MAX_BUFFERS; i++)
629*5ebc6031SPetr Machata hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp,
630*5ebc6031SPetr Machata buf->buffer_size[i]);
631*5ebc6031SPetr Machata
632*5ebc6031SPetr Machata mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom);
633*5ebc6031SPetr Machata mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom);
634*5ebc6031SPetr Machata mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
635*5ebc6031SPetr Machata return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
636*5ebc6031SPetr Machata }
637*5ebc6031SPetr Machata
638f00817dfSIdo Schimmel static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = {
6398e8dfe9fSIdo Schimmel .ieee_getets = mlxsw_sp_dcbnl_ieee_getets,
6408e8dfe9fSIdo Schimmel .ieee_setets = mlxsw_sp_dcbnl_ieee_setets,
641cc7cf517SIdo Schimmel .ieee_getmaxrate = mlxsw_sp_dcbnl_ieee_getmaxrate,
642cc7cf517SIdo Schimmel .ieee_setmaxrate = mlxsw_sp_dcbnl_ieee_setmaxrate,
643d81a6bdbSIdo Schimmel .ieee_getpfc = mlxsw_sp_dcbnl_ieee_getpfc,
644d81a6bdbSIdo Schimmel .ieee_setpfc = mlxsw_sp_dcbnl_ieee_setpfc,
645b2b1dab6SPetr Machata .ieee_setapp = mlxsw_sp_dcbnl_ieee_setapp,
646b2b1dab6SPetr Machata .ieee_delapp = mlxsw_sp_dcbnl_ieee_delapp,
6478e8dfe9fSIdo Schimmel
648f00817dfSIdo Schimmel .getdcbx = mlxsw_sp_dcbnl_getdcbx,
649f00817dfSIdo Schimmel .setdcbx = mlxsw_sp_dcbnl_setdcbx,
650*5ebc6031SPetr Machata
651*5ebc6031SPetr Machata .dcbnl_getbuffer = mlxsw_sp_dcbnl_getbuffer,
652*5ebc6031SPetr Machata .dcbnl_setbuffer = mlxsw_sp_dcbnl_setbuffer,
653f00817dfSIdo Schimmel };
654f00817dfSIdo Schimmel
mlxsw_sp_port_ets_init(struct mlxsw_sp_port * mlxsw_sp_port)6558e8dfe9fSIdo Schimmel static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
6568e8dfe9fSIdo Schimmel {
6578e8dfe9fSIdo Schimmel mlxsw_sp_port->dcb.ets = kzalloc(sizeof(*mlxsw_sp_port->dcb.ets),
6588e8dfe9fSIdo Schimmel GFP_KERNEL);
6598e8dfe9fSIdo Schimmel if (!mlxsw_sp_port->dcb.ets)
6608e8dfe9fSIdo Schimmel return -ENOMEM;
6618e8dfe9fSIdo Schimmel
6628e8dfe9fSIdo Schimmel mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
6638e8dfe9fSIdo Schimmel
6648e8dfe9fSIdo Schimmel return 0;
6658e8dfe9fSIdo Schimmel }
6668e8dfe9fSIdo Schimmel
mlxsw_sp_port_ets_fini(struct mlxsw_sp_port * mlxsw_sp_port)6678e8dfe9fSIdo Schimmel static void mlxsw_sp_port_ets_fini(struct mlxsw_sp_port *mlxsw_sp_port)
6688e8dfe9fSIdo Schimmel {
6698e8dfe9fSIdo Schimmel kfree(mlxsw_sp_port->dcb.ets);
6708e8dfe9fSIdo Schimmel }
6718e8dfe9fSIdo Schimmel
mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port * mlxsw_sp_port)672cc7cf517SIdo Schimmel static int mlxsw_sp_port_maxrate_init(struct mlxsw_sp_port *mlxsw_sp_port)
673cc7cf517SIdo Schimmel {
674cc7cf517SIdo Schimmel int i;
675cc7cf517SIdo Schimmel
676cc7cf517SIdo Schimmel mlxsw_sp_port->dcb.maxrate = kmalloc(sizeof(*mlxsw_sp_port->dcb.maxrate),
677cc7cf517SIdo Schimmel GFP_KERNEL);
678cc7cf517SIdo Schimmel if (!mlxsw_sp_port->dcb.maxrate)
679cc7cf517SIdo Schimmel return -ENOMEM;
680cc7cf517SIdo Schimmel
681cc7cf517SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
682cc7cf517SIdo Schimmel mlxsw_sp_port->dcb.maxrate->tc_maxrate[i] = MLXSW_REG_QEEC_MAS_DIS;
683cc7cf517SIdo Schimmel
684cc7cf517SIdo Schimmel return 0;
685cc7cf517SIdo Schimmel }
686cc7cf517SIdo Schimmel
mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port * mlxsw_sp_port)687cc7cf517SIdo Schimmel static void mlxsw_sp_port_maxrate_fini(struct mlxsw_sp_port *mlxsw_sp_port)
688cc7cf517SIdo Schimmel {
689cc7cf517SIdo Schimmel kfree(mlxsw_sp_port->dcb.maxrate);
690cc7cf517SIdo Schimmel }
691cc7cf517SIdo Schimmel
mlxsw_sp_port_pfc_init(struct mlxsw_sp_port * mlxsw_sp_port)692d81a6bdbSIdo Schimmel static int mlxsw_sp_port_pfc_init(struct mlxsw_sp_port *mlxsw_sp_port)
693d81a6bdbSIdo Schimmel {
694d81a6bdbSIdo Schimmel mlxsw_sp_port->dcb.pfc = kzalloc(sizeof(*mlxsw_sp_port->dcb.pfc),
695d81a6bdbSIdo Schimmel GFP_KERNEL);
696d81a6bdbSIdo Schimmel if (!mlxsw_sp_port->dcb.pfc)
697d81a6bdbSIdo Schimmel return -ENOMEM;
698d81a6bdbSIdo Schimmel
699d81a6bdbSIdo Schimmel mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
700d81a6bdbSIdo Schimmel
701d81a6bdbSIdo Schimmel return 0;
702d81a6bdbSIdo Schimmel }
703d81a6bdbSIdo Schimmel
mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port * mlxsw_sp_port)704d81a6bdbSIdo Schimmel static void mlxsw_sp_port_pfc_fini(struct mlxsw_sp_port *mlxsw_sp_port)
705d81a6bdbSIdo Schimmel {
706d81a6bdbSIdo Schimmel kfree(mlxsw_sp_port->dcb.pfc);
707d81a6bdbSIdo Schimmel }
708d81a6bdbSIdo Schimmel
mlxsw_sp_port_dcb_init(struct mlxsw_sp_port * mlxsw_sp_port)709f00817dfSIdo Schimmel int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port)
710f00817dfSIdo Schimmel {
7118e8dfe9fSIdo Schimmel int err;
7128e8dfe9fSIdo Schimmel
7138e8dfe9fSIdo Schimmel err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
7148e8dfe9fSIdo Schimmel if (err)
7158e8dfe9fSIdo Schimmel return err;
716cc7cf517SIdo Schimmel err = mlxsw_sp_port_maxrate_init(mlxsw_sp_port);
717cc7cf517SIdo Schimmel if (err)
718cc7cf517SIdo Schimmel goto err_port_maxrate_init;
719d81a6bdbSIdo Schimmel err = mlxsw_sp_port_pfc_init(mlxsw_sp_port);
720d81a6bdbSIdo Schimmel if (err)
721d81a6bdbSIdo Schimmel goto err_port_pfc_init;
7228e8dfe9fSIdo Schimmel
723b2b1dab6SPetr Machata mlxsw_sp_port->dcb.trust_state = MLXSW_REG_QPTS_TRUST_STATE_PCP;
724f00817dfSIdo Schimmel mlxsw_sp_port->dev->dcbnl_ops = &mlxsw_sp_dcbnl_ops;
725f00817dfSIdo Schimmel
726f00817dfSIdo Schimmel return 0;
727cc7cf517SIdo Schimmel
728d81a6bdbSIdo Schimmel err_port_pfc_init:
729d81a6bdbSIdo Schimmel mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
730cc7cf517SIdo Schimmel err_port_maxrate_init:
731cc7cf517SIdo Schimmel mlxsw_sp_port_ets_fini(mlxsw_sp_port);
732cc7cf517SIdo Schimmel return err;
733f00817dfSIdo Schimmel }
734f00817dfSIdo Schimmel
mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port * mlxsw_sp_port)735f00817dfSIdo Schimmel void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
736f00817dfSIdo Schimmel {
737d81a6bdbSIdo Schimmel mlxsw_sp_port_pfc_fini(mlxsw_sp_port);
738cc7cf517SIdo Schimmel mlxsw_sp_port_maxrate_fini(mlxsw_sp_port);
7398e8dfe9fSIdo Schimmel mlxsw_sp_port_ets_fini(mlxsw_sp_port);
740f00817dfSIdo Schimmel }
741