.. | .. |
---|
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) |
---|