Skip to content

Commit 18e9a40

Browse files
committed
Merge branch 'mlxsw-Refactor-headroom-management'
Ido Schimmel says: ==================== mlxsw: Refactor headroom management Petr says: On Spectrum, port buffers, also called port headroom, is where packets are stored while they are parsed and the forwarding decision is being made. For lossless traffic flows, in case shared buffer admission is not allowed, headroom is also where to put the extra traffic received before the sent PAUSE takes effect. Another aspect of the port headroom is the so called internal buffer, which is used for egress mirroring. Linux supports two DCB interfaces related to the headroom: dcbnl_setbuffer for configuration, and dcbnl_getbuffer for inspection. In order to make it possible to implement these interfaces, it is first necessary to clean up headroom handling, which is currently strewn in several places in the driver. The end goal is an architecture whereby it is possible to take a copy of the current configuration, adjust parameters, and then hand the proposed configuration over to the system to implement it. When everything works, the proposed configuration is accepted and saved. First, this centralizes the reconfiguration handling to one function, which takes care of coordinating buffer size changes and priority map changes to avoid introducing drops. Second, the fact that the configuration is all in one place makes it easy to keep a backup and handle error path rollbacks, which were previously hard to understand. Patch #1 introduces struct mlxsw_sp_hdroom, which will keep port headroom configuration. Patch #2 unifies handling of delay provision between PFC and PAUSE. From now on, delay is to be measured in bytes of extra space, and will not include MTU. PFC handler sets the delay directly from the parameter it gets through the DCB interface. For PAUSE, MLXSW_SP_PAUSE_DELAY is converted to have the same meaning. In patches #3-#5, MTU, lossiness and priorities are gradually moved over to struct mlxsw_sp_hdroom. In patches #6-#11, handling of buffer resizing and priority maps is moved from spectrum.c and spectrum_dcb.c to spectrum_buffers.c. The API is gradually adapted so that struct mlxsw_sp_hdroom becomes the main interface through which the various clients express how the headroom should be configured. Patch #12 is a small cleanup that the previous transformation made possible. In patch #13, the port init code becomes a boring client of the headroom code, instead of rolling its own thing. Patches #14 and #15 move handling of internal mirroring buffer to the new headroom code as well. Previously, this code was in the SPAN module. This patchset converts the SPAN module to another boring client of the headroom code. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 045e42f + 22881ad commit 18e9a40

File tree

7 files changed

+470
-295
lines changed

7 files changed

+470
-295
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 18 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -610,138 +610,33 @@ static int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p)
610610
return 0;
611611
}
612612

613-
static u16 mlxsw_sp_pg_buf_threshold_get(const struct mlxsw_sp *mlxsw_sp,
614-
int mtu)
615-
{
616-
return 2 * mlxsw_sp_bytes_cells(mlxsw_sp, mtu);
617-
}
618-
619-
#define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */
620-
621-
static u16 mlxsw_sp_pfc_delay_get(const struct mlxsw_sp *mlxsw_sp, int mtu,
622-
u16 delay)
623-
{
624-
delay = mlxsw_sp_bytes_cells(mlxsw_sp, DIV_ROUND_UP(delay,
625-
BITS_PER_BYTE));
626-
return MLXSW_SP_CELL_FACTOR * delay + mlxsw_sp_bytes_cells(mlxsw_sp,
627-
mtu);
628-
}
629-
630-
/* Maximum delay buffer needed in case of PAUSE frames, in bytes.
631-
* Assumes 100m cable and maximum MTU.
632-
*/
633-
#define MLXSW_SP_PAUSE_DELAY 58752
634-
635-
static u16 mlxsw_sp_pg_buf_delay_get(const struct mlxsw_sp *mlxsw_sp, int mtu,
636-
u16 delay, bool pfc, bool pause)
637-
{
638-
if (pfc)
639-
return mlxsw_sp_pfc_delay_get(mlxsw_sp, mtu, delay);
640-
else if (pause)
641-
return mlxsw_sp_bytes_cells(mlxsw_sp, MLXSW_SP_PAUSE_DELAY);
642-
else
643-
return 0;
644-
}
645-
646-
static void mlxsw_sp_pg_buf_pack(char *pbmc_pl, int index, u16 size, u16 thres,
647-
bool lossy)
613+
static int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)
648614
{
649-
if (lossy)
650-
mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, index, size);
651-
else
652-
mlxsw_reg_pbmc_lossless_buffer_pack(pbmc_pl, index, size,
653-
thres);
654-
}
615+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
616+
struct mlxsw_sp_hdroom orig_hdroom;
617+
struct mlxsw_sp_hdroom hdroom;
618+
int err;
655619

656-
int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
657-
u8 *prio_tc, bool pause_en,
658-
struct ieee_pfc *my_pfc)
659-
{
660-
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
661-
u8 pfc_en = !!my_pfc ? my_pfc->pfc_en : 0;
662-
u16 delay = !!my_pfc ? my_pfc->delay : 0;
663-
char pbmc_pl[MLXSW_REG_PBMC_LEN];
664-
u32 taken_headroom_cells = 0;
665-
u32 max_headroom_cells;
666-
int i, j, err;
620+
orig_hdroom = *mlxsw_sp_port->hdroom;
667621

668-
max_headroom_cells = mlxsw_sp_sb_max_headroom_cells(mlxsw_sp);
622+
hdroom = orig_hdroom;
623+
hdroom.mtu = mtu;
624+
mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
669625

670-
mlxsw_reg_pbmc_pack(pbmc_pl, mlxsw_sp_port->local_port, 0, 0);
671-
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl);
672-
if (err)
626+
err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
627+
if (err) {
628+
netdev_err(dev, "Failed to configure port's headroom\n");
673629
return err;
674-
675-
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
676-
bool configure = false;
677-
bool pfc = false;
678-
u16 thres_cells;
679-
u16 delay_cells;
680-
u16 total_cells;
681-
bool lossy;
682-
683-
for (j = 0; j < IEEE_8021QAZ_MAX_TCS; j++) {
684-
if (prio_tc[j] == i) {
685-
pfc = pfc_en & BIT(j);
686-
configure = true;
687-
break;
688-
}
689-
}
690-
691-
if (!configure)
692-
continue;
693-
694-
lossy = !(pfc || pause_en);
695-
thres_cells = mlxsw_sp_pg_buf_threshold_get(mlxsw_sp, mtu);
696-
thres_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, thres_cells);
697-
delay_cells = mlxsw_sp_pg_buf_delay_get(mlxsw_sp, mtu, delay,
698-
pfc, pause_en);
699-
delay_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, delay_cells);
700-
total_cells = thres_cells + delay_cells;
701-
702-
taken_headroom_cells += total_cells;
703-
if (taken_headroom_cells > max_headroom_cells)
704-
return -ENOBUFS;
705-
706-
mlxsw_sp_pg_buf_pack(pbmc_pl, i, total_cells,
707-
thres_cells, lossy);
708630
}
709631

710-
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pbmc), pbmc_pl);
711-
}
712-
713-
int mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port,
714-
int mtu, bool pause_en)
715-
{
716-
u8 def_prio_tc[IEEE_8021QAZ_MAX_TCS] = {0};
717-
bool dcb_en = !!mlxsw_sp_port->dcb.ets;
718-
struct ieee_pfc *my_pfc;
719-
u8 *prio_tc;
720-
721-
prio_tc = dcb_en ? mlxsw_sp_port->dcb.ets->prio_tc : def_prio_tc;
722-
my_pfc = dcb_en ? mlxsw_sp_port->dcb.pfc : NULL;
723-
724-
return __mlxsw_sp_port_headroom_set(mlxsw_sp_port, mtu, prio_tc,
725-
pause_en, my_pfc);
726-
}
727-
728-
static int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)
729-
{
730-
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
731-
bool pause_en = mlxsw_sp_port_is_pause_en(mlxsw_sp_port);
732-
int err;
733-
734-
err = mlxsw_sp_port_headroom_set(mlxsw_sp_port, mtu, pause_en);
735-
if (err)
736-
return err;
737632
err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu);
738633
if (err)
739634
goto err_port_mtu_set;
740635
dev->mtu = mtu;
741636
return 0;
742637

743638
err_port_mtu_set:
744-
mlxsw_sp_port_headroom_set(mlxsw_sp_port, dev->mtu, pause_en);
639+
mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
745640
return err;
746641
}
747642

@@ -1709,6 +1604,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
17091604
mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
17101605
err_port_tc_mc_mode:
17111606
err_port_ets_init:
1607+
mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
17121608
err_port_buffers_init:
17131609
err_port_admin_status_set:
17141610
err_port_mtu_set:
@@ -1745,6 +1641,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
17451641
mlxsw_sp_port_fids_fini(mlxsw_sp_port);
17461642
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
17471643
mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
1644+
mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
17481645
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
17491646
mlxsw_sp_port_module_unmap(mlxsw_sp_port);
17501647
free_percpu(mlxsw_sp_port->pcpu_stats);
@@ -2800,6 +2697,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
28002697
mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;
28012698
mlxsw_sp->rif_ops_arr = mlxsw_sp1_rif_ops_arr;
28022699
mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;
2700+
mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops;
28032701
mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops;
28042702
mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;
28052703
mlxsw_sp->span_ops = &mlxsw_sp1_span_ops;
@@ -2828,6 +2726,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
28282726
mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
28292727
mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
28302728
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
2729+
mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops;
28312730
mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
28322731
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
28332732
mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;
@@ -2854,6 +2753,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
28542753
mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
28552754
mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
28562755
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
2756+
mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;
28572757
mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
28582758
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
28592759
mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct mlxsw_sp_mr_tcam_ops;
125125
struct mlxsw_sp_acl_rulei_ops;
126126
struct mlxsw_sp_acl_tcam_ops;
127127
struct mlxsw_sp_nve_ops;
128+
struct mlxsw_sp_sb_ops;
128129
struct mlxsw_sp_sb_vals;
129130
struct mlxsw_sp_port_type_speed_ops;
130131
struct mlxsw_sp_ptp_state;
@@ -171,6 +172,7 @@ struct mlxsw_sp {
171172
const struct mlxsw_sp_nve_ops **nve_ops_arr;
172173
const struct mlxsw_sp_rif_ops **rif_ops_arr;
173174
const struct mlxsw_sp_sb_vals *sb_vals;
175+
const struct mlxsw_sp_sb_ops *sb_ops;
174176
const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;
175177
const struct mlxsw_sp_ptp_ops *ptp_ops;
176178
const struct mlxsw_sp_span_ops *span_ops;
@@ -316,6 +318,7 @@ struct mlxsw_sp_port {
316318
u8 split_base_local_port;
317319
int max_mtu;
318320
u32 max_speed;
321+
struct mlxsw_sp_hdroom *hdroom;
319322
};
320323

321324
struct mlxsw_sp_port_type_speed_ops {
@@ -412,34 +415,62 @@ mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port,
412415
return NULL;
413416
}
414417

415-
static inline u32
416-
mlxsw_sp_port_headroom_8x_adjust(const struct mlxsw_sp_port *mlxsw_sp_port,
417-
u32 size_cells)
418-
{
419-
/* Ports with eight lanes use two headroom buffers between which the
420-
* configured headroom size is split. Therefore, multiply the calculated
421-
* headroom size by two.
422-
*/
423-
return mlxsw_sp_port->mapping.width == 8 ? 2 * size_cells : size_cells;
424-
}
425-
426418
enum mlxsw_sp_flood_type {
427419
MLXSW_SP_FLOOD_TYPE_UC,
428420
MLXSW_SP_FLOOD_TYPE_BC,
429421
MLXSW_SP_FLOOD_TYPE_MC,
430422
};
431423

432-
int mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port,
433-
int mtu, bool pause_en);
434424
int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
435425
int prio, char *ppcnt_pl);
436426
int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
437427
bool is_up);
438428

439429
/* spectrum_buffers.c */
430+
struct mlxsw_sp_hdroom_prio {
431+
/* Number of port buffer associated with this priority. This is the
432+
* actually configured value.
433+
*/
434+
u8 buf_idx;
435+
/* Value of buf_idx deduced from the DCB ETS configuration. */
436+
u8 ets_buf_idx;
437+
bool lossy;
438+
};
439+
440+
struct mlxsw_sp_hdroom_buf {
441+
u32 thres_cells;
442+
u32 size_cells;
443+
bool lossy;
444+
};
445+
446+
#define MLXSW_SP_PB_COUNT 10
447+
448+
struct mlxsw_sp_hdroom {
449+
struct {
450+
struct mlxsw_sp_hdroom_prio prio[IEEE_8021Q_MAX_PRIORITIES];
451+
} prios;
452+
struct {
453+
struct mlxsw_sp_hdroom_buf buf[MLXSW_SP_PB_COUNT];
454+
} bufs;
455+
struct {
456+
/* Size actually configured for the internal buffer. Equal to
457+
* reserve when internal buffer is enabled.
458+
*/
459+
u32 size_cells;
460+
/* Space reserved in the headroom for the internal buffer. Port
461+
* buffers are not allowed to grow into this space.
462+
*/
463+
u32 reserve_cells;
464+
bool enable;
465+
} int_buf;
466+
int delay_bytes;
467+
int mtu;
468+
};
469+
440470
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp);
441471
void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp);
442472
int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port);
473+
void mlxsw_sp_port_buffers_fini(struct mlxsw_sp_port *mlxsw_sp_port);
443474
int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
444475
unsigned int sb_index, u16 pool_index,
445476
struct devlink_sb_pool_info *pool_info);
@@ -475,11 +506,20 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
475506
u32 *p_cur, u32 *p_max);
476507
u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells);
477508
u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes);
478-
u32 mlxsw_sp_sb_max_headroom_cells(const struct mlxsw_sp *mlxsw_sp);
509+
void mlxsw_sp_hdroom_prios_reset_buf_idx(struct mlxsw_sp_hdroom *hdroom);
510+
void mlxsw_sp_hdroom_bufs_reset_lossiness(struct mlxsw_sp_hdroom *hdroom);
511+
void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
512+
struct mlxsw_sp_hdroom *hdroom);
513+
int mlxsw_sp_hdroom_configure(struct mlxsw_sp_port *mlxsw_sp_port,
514+
const struct mlxsw_sp_hdroom *hdroom);
479515

480516
extern const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals;
481517
extern const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals;
482518

519+
extern const struct mlxsw_sp_sb_ops mlxsw_sp1_sb_ops;
520+
extern const struct mlxsw_sp_sb_ops mlxsw_sp2_sb_ops;
521+
extern const struct mlxsw_sp_sb_ops mlxsw_sp3_sb_ops;
522+
483523
/* spectrum_switchdev.c */
484524
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);
485525
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp);
@@ -517,9 +557,6 @@ int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
517557
bool dwrr, u8 dwrr_weight);
518558
int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
519559
u8 switch_prio, u8 tclass);
520-
int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
521-
u8 *prio_tc, bool pause_en,
522-
struct ieee_pfc *my_pfc);
523560
int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
524561
enum mlxsw_reg_qeec_hr hr, u8 index,
525562
u8 next_index, u32 maxrate, u8 burst_size);

0 commit comments

Comments
 (0)