| .. | .. |
|---|
| 64 | 64 | return 0; |
|---|
| 65 | 65 | } |
|---|
| 66 | 66 | |
|---|
| 67 | | -static int mlxsw_sp_port_pg_prio_map(struct mlxsw_sp_port *mlxsw_sp_port, |
|---|
| 68 | | - u8 *prio_tc) |
|---|
| 67 | +static int mlxsw_sp_port_headroom_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, |
|---|
| 68 | + struct ieee_ets *ets) |
|---|
| 69 | 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 | 70 | struct net_device *dev = mlxsw_sp_port->dev; |
|---|
| 71 | + struct mlxsw_sp_hdroom hdroom; |
|---|
| 72 | + int prio; |
|---|
| 119 | 73 | int err; |
|---|
| 120 | 74 | |
|---|
| 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); |
|---|
| 75 | + hdroom = *mlxsw_sp_port->hdroom; |
|---|
| 76 | + for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) |
|---|
| 77 | + hdroom.prios.prio[prio].ets_buf_idx = ets->prio_tc[prio]; |
|---|
| 78 | + mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom); |
|---|
| 79 | + mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); |
|---|
| 80 | + mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); |
|---|
| 81 | + |
|---|
| 82 | + err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); |
|---|
| 127 | 83 | if (err) { |
|---|
| 128 | 84 | netdev_err(dev, "Failed to configure port's headroom\n"); |
|---|
| 129 | 85 | return err; |
|---|
| 130 | 86 | } |
|---|
| 131 | 87 | |
|---|
| 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 | 88 | 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 | 89 | } |
|---|
| 149 | 90 | |
|---|
| 150 | 91 | static int __mlxsw_sp_dcbnl_ieee_setets(struct mlxsw_sp_port *mlxsw_sp_port, |
|---|
| .. | .. |
|---|
| 160 | 101 | u8 weight = ets->tc_tx_bw[i]; |
|---|
| 161 | 102 | |
|---|
| 162 | 103 | err = mlxsw_sp_port_ets_set(mlxsw_sp_port, |
|---|
| 163 | | - MLXSW_REG_QEEC_HIERARCY_SUBGROUP, i, |
|---|
| 104 | + MLXSW_REG_QEEC_HR_SUBGROUP, i, |
|---|
| 164 | 105 | 0, dwrr, weight); |
|---|
| 165 | 106 | if (err) { |
|---|
| 166 | 107 | netdev_err(dev, "Failed to link subgroup ETS element %d to group\n", |
|---|
| .. | .. |
|---|
| 180 | 121 | } |
|---|
| 181 | 122 | |
|---|
| 182 | 123 | /* Ingress configuration. */ |
|---|
| 183 | | - err = mlxsw_sp_port_headroom_set(mlxsw_sp_port, ets); |
|---|
| 124 | + err = mlxsw_sp_port_headroom_ets_set(mlxsw_sp_port, ets); |
|---|
| 184 | 125 | if (err) |
|---|
| 185 | 126 | goto err_port_headroom_set; |
|---|
| 186 | 127 | |
|---|
| .. | .. |
|---|
| 198 | 139 | u8 weight = my_ets->tc_tx_bw[i]; |
|---|
| 199 | 140 | |
|---|
| 200 | 141 | err = mlxsw_sp_port_ets_set(mlxsw_sp_port, |
|---|
| 201 | | - MLXSW_REG_QEEC_HIERARCY_SUBGROUP, i, |
|---|
| 142 | + MLXSW_REG_QEEC_HR_SUBGROUP, i, |
|---|
| 202 | 143 | 0, dwrr, weight); |
|---|
| 203 | 144 | } |
|---|
| 204 | 145 | return err; |
|---|
| .. | .. |
|---|
| 227 | 168 | static int mlxsw_sp_dcbnl_app_validate(struct net_device *dev, |
|---|
| 228 | 169 | struct dcb_app *app) |
|---|
| 229 | 170 | { |
|---|
| 230 | | - int prio; |
|---|
| 231 | | - |
|---|
| 232 | 171 | if (app->priority >= IEEE_8021QAZ_MAX_TCS) { |
|---|
| 233 | 172 | netdev_err(dev, "APP entry with priority value %u is invalid\n", |
|---|
| 234 | 173 | app->priority); |
|---|
| .. | .. |
|---|
| 241 | 180 | netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n", |
|---|
| 242 | 181 | app->protocol); |
|---|
| 243 | 182 | 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 | 183 | } |
|---|
| 256 | 184 | break; |
|---|
| 257 | 185 | |
|---|
| .. | .. |
|---|
| 369 | 297 | } |
|---|
| 370 | 298 | |
|---|
| 371 | 299 | static int |
|---|
| 300 | +mlxsw_sp_port_dcb_app_update_qpdp(struct mlxsw_sp_port *mlxsw_sp_port, |
|---|
| 301 | + u8 default_prio) |
|---|
| 302 | +{ |
|---|
| 303 | + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
|---|
| 304 | + char qpdp_pl[MLXSW_REG_QPDP_LEN]; |
|---|
| 305 | + |
|---|
| 306 | + mlxsw_reg_qpdp_pack(qpdp_pl, mlxsw_sp_port->local_port, default_prio); |
|---|
| 307 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpdp), qpdp_pl); |
|---|
| 308 | +} |
|---|
| 309 | + |
|---|
| 310 | +static int |
|---|
| 372 | 311 | mlxsw_sp_port_dcb_app_update_qpdpm(struct mlxsw_sp_port *mlxsw_sp_port, |
|---|
| 373 | 312 | struct dcb_ieee_app_dscp_map *map) |
|---|
| 374 | 313 | { |
|---|
| .. | .. |
|---|
| 405 | 344 | int err; |
|---|
| 406 | 345 | |
|---|
| 407 | 346 | default_prio = mlxsw_sp_port_dcb_app_default_prio(mlxsw_sp_port); |
|---|
| 347 | + err = mlxsw_sp_port_dcb_app_update_qpdp(mlxsw_sp_port, default_prio); |
|---|
| 348 | + if (err) { |
|---|
| 349 | + netdev_err(mlxsw_sp_port->dev, "Couldn't configure port default priority\n"); |
|---|
| 350 | + return err; |
|---|
| 351 | + } |
|---|
| 352 | + |
|---|
| 408 | 353 | have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port, |
|---|
| 409 | 354 | &prio_map); |
|---|
| 410 | 355 | |
|---|
| .. | .. |
|---|
| 507 | 452 | |
|---|
| 508 | 453 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { |
|---|
| 509 | 454 | err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, |
|---|
| 510 | | - MLXSW_REG_QEEC_HIERARCY_SUBGROUP, |
|---|
| 455 | + MLXSW_REG_QEEC_HR_SUBGROUP, |
|---|
| 511 | 456 | i, 0, |
|---|
| 512 | | - maxrate->tc_maxrate[i]); |
|---|
| 457 | + maxrate->tc_maxrate[i], 0); |
|---|
| 513 | 458 | if (err) { |
|---|
| 514 | 459 | netdev_err(dev, "Failed to set maxrate for TC %d\n", i); |
|---|
| 515 | 460 | goto err_port_ets_maxrate_set; |
|---|
| .. | .. |
|---|
| 523 | 468 | err_port_ets_maxrate_set: |
|---|
| 524 | 469 | for (i--; i >= 0; i--) |
|---|
| 525 | 470 | mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, |
|---|
| 526 | | - MLXSW_REG_QEEC_HIERARCY_SUBGROUP, |
|---|
| 527 | | - i, 0, my_maxrate->tc_maxrate[i]); |
|---|
| 471 | + MLXSW_REG_QEEC_HR_SUBGROUP, |
|---|
| 472 | + i, 0, |
|---|
| 473 | + my_maxrate->tc_maxrate[i], 0); |
|---|
| 528 | 474 | return err; |
|---|
| 529 | 475 | } |
|---|
| 530 | 476 | |
|---|
| .. | .. |
|---|
| 587 | 533 | { |
|---|
| 588 | 534 | struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
|---|
| 589 | 535 | bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port); |
|---|
| 536 | + struct mlxsw_sp_hdroom orig_hdroom; |
|---|
| 537 | + struct mlxsw_sp_hdroom hdroom; |
|---|
| 538 | + int prio; |
|---|
| 590 | 539 | int err; |
|---|
| 591 | 540 | |
|---|
| 592 | 541 | if (pause_en && pfc->pfc_en) { |
|---|
| .. | .. |
|---|
| 594 | 543 | return -EINVAL; |
|---|
| 595 | 544 | } |
|---|
| 596 | 545 | |
|---|
| 597 | | - err = __mlxsw_sp_port_headroom_set(mlxsw_sp_port, dev->mtu, |
|---|
| 598 | | - mlxsw_sp_port->dcb.ets->prio_tc, |
|---|
| 599 | | - pause_en, pfc); |
|---|
| 546 | + orig_hdroom = *mlxsw_sp_port->hdroom; |
|---|
| 547 | + |
|---|
| 548 | + hdroom = orig_hdroom; |
|---|
| 549 | + if (pfc->pfc_en) |
|---|
| 550 | + hdroom.delay_bytes = DIV_ROUND_UP(pfc->delay, BITS_PER_BYTE); |
|---|
| 551 | + else |
|---|
| 552 | + hdroom.delay_bytes = 0; |
|---|
| 553 | + |
|---|
| 554 | + for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) |
|---|
| 555 | + hdroom.prios.prio[prio].lossy = !(pfc->pfc_en & BIT(prio)); |
|---|
| 556 | + |
|---|
| 557 | + mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); |
|---|
| 558 | + mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); |
|---|
| 559 | + |
|---|
| 560 | + err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); |
|---|
| 600 | 561 | if (err) { |
|---|
| 601 | 562 | netdev_err(dev, "Failed to configure port's headroom for PFC\n"); |
|---|
| 602 | 563 | return err; |
|---|
| .. | .. |
|---|
| 614 | 575 | return 0; |
|---|
| 615 | 576 | |
|---|
| 616 | 577 | 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); |
|---|
| 578 | + mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom); |
|---|
| 620 | 579 | return err; |
|---|
| 580 | +} |
|---|
| 581 | + |
|---|
| 582 | +static int mlxsw_sp_dcbnl_getbuffer(struct net_device *dev, struct dcbnl_buffer *buf) |
|---|
| 583 | +{ |
|---|
| 584 | + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
|---|
| 585 | + struct mlxsw_sp_hdroom *hdroom = mlxsw_sp_port->hdroom; |
|---|
| 586 | + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
|---|
| 587 | + int prio; |
|---|
| 588 | + int i; |
|---|
| 589 | + |
|---|
| 590 | + buf->total_size = 0; |
|---|
| 591 | + |
|---|
| 592 | + BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT); |
|---|
| 593 | + for (i = 0; i < MLXSW_SP_PB_COUNT; i++) { |
|---|
| 594 | + u32 bytes = mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->bufs.buf[i].size_cells); |
|---|
| 595 | + |
|---|
| 596 | + if (i < DCBX_MAX_BUFFERS) |
|---|
| 597 | + buf->buffer_size[i] = bytes; |
|---|
| 598 | + buf->total_size += bytes; |
|---|
| 599 | + } |
|---|
| 600 | + |
|---|
| 601 | + buf->total_size += mlxsw_sp_cells_bytes(mlxsw_sp, hdroom->int_buf.size_cells); |
|---|
| 602 | + |
|---|
| 603 | + for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++) |
|---|
| 604 | + buf->prio2buffer[prio] = hdroom->prios.prio[prio].buf_idx; |
|---|
| 605 | + |
|---|
| 606 | + return 0; |
|---|
| 607 | +} |
|---|
| 608 | + |
|---|
| 609 | +static int mlxsw_sp_dcbnl_setbuffer(struct net_device *dev, struct dcbnl_buffer *buf) |
|---|
| 610 | +{ |
|---|
| 611 | + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); |
|---|
| 612 | + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; |
|---|
| 613 | + struct mlxsw_sp_hdroom hdroom; |
|---|
| 614 | + int prio; |
|---|
| 615 | + int i; |
|---|
| 616 | + |
|---|
| 617 | + hdroom = *mlxsw_sp_port->hdroom; |
|---|
| 618 | + |
|---|
| 619 | + if (hdroom.mode != MLXSW_SP_HDROOM_MODE_TC) { |
|---|
| 620 | + netdev_err(dev, "The use of dcbnl_setbuffer is only allowed if egress is configured using TC\n"); |
|---|
| 621 | + return -EINVAL; |
|---|
| 622 | + } |
|---|
| 623 | + |
|---|
| 624 | + for (prio = 0; prio < IEEE_8021Q_MAX_PRIORITIES; prio++) |
|---|
| 625 | + hdroom.prios.prio[prio].set_buf_idx = buf->prio2buffer[prio]; |
|---|
| 626 | + |
|---|
| 627 | + BUILD_BUG_ON(DCBX_MAX_BUFFERS > MLXSW_SP_PB_COUNT); |
|---|
| 628 | + for (i = 0; i < DCBX_MAX_BUFFERS; i++) |
|---|
| 629 | + hdroom.bufs.buf[i].set_size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, |
|---|
| 630 | + buf->buffer_size[i]); |
|---|
| 631 | + |
|---|
| 632 | + mlxsw_sp_hdroom_prios_reset_buf_idx(&hdroom); |
|---|
| 633 | + mlxsw_sp_hdroom_bufs_reset_lossiness(&hdroom); |
|---|
| 634 | + mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); |
|---|
| 635 | + return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); |
|---|
| 621 | 636 | } |
|---|
| 622 | 637 | |
|---|
| 623 | 638 | static const struct dcbnl_rtnl_ops mlxsw_sp_dcbnl_ops = { |
|---|
| .. | .. |
|---|
| 632 | 647 | |
|---|
| 633 | 648 | .getdcbx = mlxsw_sp_dcbnl_getdcbx, |
|---|
| 634 | 649 | .setdcbx = mlxsw_sp_dcbnl_setdcbx, |
|---|
| 650 | + |
|---|
| 651 | + .dcbnl_getbuffer = mlxsw_sp_dcbnl_getbuffer, |
|---|
| 652 | + .dcbnl_setbuffer = mlxsw_sp_dcbnl_setbuffer, |
|---|
| 635 | 653 | }; |
|---|
| 636 | 654 | |
|---|
| 637 | 655 | static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) |
|---|