root/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_dcbnl_getdcbx
  2. mlxsw_sp_dcbnl_setdcbx
  3. mlxsw_sp_dcbnl_ieee_getets
  4. mlxsw_sp_port_ets_validate
  5. mlxsw_sp_port_pg_prio_map
  6. mlxsw_sp_ets_has_pg
  7. mlxsw_sp_port_pg_destroy
  8. mlxsw_sp_port_headroom_set
  9. __mlxsw_sp_dcbnl_ieee_setets
  10. mlxsw_sp_dcbnl_ieee_setets
  11. mlxsw_sp_dcbnl_app_validate
  12. mlxsw_sp_port_dcb_app_default_prio
  13. mlxsw_sp_port_dcb_app_dscp_prio_map
  14. mlxsw_sp_port_dcb_app_prio_dscp_map
  15. mlxsw_sp_port_dcb_app_update_qpts
  16. mlxsw_sp_port_dcb_app_update_qrwe
  17. mlxsw_sp_port_dcb_toggle_trust
  18. mlxsw_sp_port_dcb_app_update_qpdpm
  19. mlxsw_sp_port_dcb_app_update_qpdsm
  20. mlxsw_sp_port_dcb_app_update
  21. mlxsw_sp_dcbnl_ieee_setapp
  22. mlxsw_sp_dcbnl_ieee_delapp
  23. mlxsw_sp_dcbnl_ieee_getmaxrate
  24. mlxsw_sp_dcbnl_ieee_setmaxrate
  25. mlxsw_sp_port_pfc_cnt_get
  26. mlxsw_sp_dcbnl_ieee_getpfc
  27. mlxsw_sp_port_pfc_set
  28. mlxsw_sp_dcbnl_ieee_setpfc
  29. mlxsw_sp_port_ets_init
  30. mlxsw_sp_port_ets_fini
  31. mlxsw_sp_port_maxrate_init
  32. mlxsw_sp_port_maxrate_fini
  33. mlxsw_sp_port_pfc_init
  34. mlxsw_sp_port_pfc_fini
  35. mlxsw_sp_port_dcb_init
  36. mlxsw_sp_port_dcb_fini

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

/* [<][>][^][v][top][bottom][index][help] */