Commit 58a01d4d authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-dcb'

Jiri Pirko says:

====================
mlxsw: Introduce support for Data Center Bridging

Ido says:

This patchset introduces support for Quality of Service (QoS) as part of the
IEEE Data Center Bridiging (DCB) standards.

Patches 1-9 do the required device initialization. Specifically, patches 1-6
initialize the ports' headroom buffers, which are used at ingress to store
incoming packets while they go through the switch's pipeline. Patches 7-9
complete them by initializing the egress scheduling.

The pipeline mentioned above determines the packet's egress port(s) and
traffic class. Ideally, once out of the pipeline the packet moves to the
switch's shared buffer (to be introduced in Jiri's patchset, currently
default values are used) and scheduled for transmission according to its
traffic class. The egress scheduling is configured according to the 802.1Qaz
standard, which is part of the DCB infrastructure supported by Linux. This
is introduced in patches 10-12.

Even after going through the pipeline packets are not always eligible to
enter the shared buffer. This is determined by the amount of available space
and the quotas associated with the packet. However, if flow control is
enabled and the packet is associated with the lossless flow, then it will
stay in the headroom and won't be discarded. This is introduced in patches
13-17.

Please check individual commit messages for more info, as I tried to keep
them pretty detailed.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 92b6d35f d81a6bdb
......@@ -50,3 +50,11 @@ config MLXSW_SPECTRUM
To compile this driver as a module, choose M here: the
module will be called mlxsw_spectrum.
config MLXSW_SPECTRUM_DCB
bool "Data Center Bridging (DCB) support"
depends on MLXSW_SPECTRUM && DCB
default y
---help---
Say Y here if you want to use Data Center Bridging (DCB) in the
driver.
......@@ -8,3 +8,4 @@ mlxsw_switchx2-objs := switchx2.o
obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o
mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_switchdev.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
This diff is collapsed.
......@@ -42,6 +42,7 @@
#include <linux/bitops.h>
#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/dcbnl.h>
#include <net/switchdev.h>
#include <net/devlink.h>
......@@ -62,6 +63,23 @@
#define MLXSW_SP_PORT_BASE_SPEED 25000 /* Mb/s */
#define MLXSW_SP_BYTES_PER_CELL 96
#define MLXSW_SP_BYTES_TO_CELLS(b) DIV_ROUND_UP(b, MLXSW_SP_BYTES_PER_CELL)
/* Maximum delay buffer needed in case of PAUSE frames, in cells.
* Assumes 100m cable and maximum MTU.
*/
#define MLXSW_SP_PAUSE_DELAY 612
#define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */
static inline u16 mlxsw_sp_pfc_delay_get(int mtu, u16 delay)
{
delay = MLXSW_SP_BYTES_TO_CELLS(DIV_ROUND_UP(delay, BITS_PER_BYTE));
return MLXSW_SP_CELL_FACTOR * delay + MLXSW_SP_BYTES_TO_CELLS(mtu);
}
struct mlxsw_sp_port;
struct mlxsw_sp_upper {
......@@ -166,6 +184,15 @@ struct mlxsw_sp_port {
struct mlxsw_sp_vfid *vfid;
u16 vid;
} vport;
struct {
u8 tx_pause:1,
rx_pause:1;
} link;
struct {
struct ieee_ets *ets;
struct ieee_maxrate *maxrate;
struct ieee_pfc *pfc;
} dcb;
/* 802.1Q bridge VLANs */
unsigned long *active_vlans;
unsigned long *untagged_vlans;
......@@ -174,6 +201,12 @@ struct mlxsw_sp_port {
struct devlink_port devlink_port;
};
static inline bool
mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
{
return mlxsw_sp_port->link.tx_pause || mlxsw_sp_port->link.rx_pause;
}
static inline struct mlxsw_sp_port *
mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index)
{
......@@ -265,5 +298,33 @@ int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
bool set, bool only_uc);
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
bool dwrr, u8 dwrr_weight);
int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
u8 switch_prio, u8 tclass);
int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu,
u8 *prio_tc, bool pause_en,
struct ieee_pfc *my_pfc);
int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
enum mlxsw_reg_qeec_hr hr, u8 index,
u8 next_index, u32 maxrate);
#ifdef CONFIG_MLXSW_SPECTRUM_DCB
int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port);
void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port);
#else
static inline int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
return 0;
}
static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
{}
#endif
#endif
......@@ -34,6 +34,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/dcbnl.h>
#include <linux/if_ether.h>
#include "spectrum.h"
#include "core.h"
......@@ -52,15 +54,15 @@ struct mlxsw_sp_pb {
}
static const struct mlxsw_sp_pb mlxsw_sp_pbs[] = {
MLXSW_SP_PB(0, 208),
MLXSW_SP_PB(1, 208),
MLXSW_SP_PB(2, 208),
MLXSW_SP_PB(3, 208),
MLXSW_SP_PB(4, 208),
MLXSW_SP_PB(5, 208),
MLXSW_SP_PB(6, 208),
MLXSW_SP_PB(7, 208),
MLXSW_SP_PB(9, 208),
MLXSW_SP_PB(0, 2 * MLXSW_SP_BYTES_TO_CELLS(ETH_FRAME_LEN)),
MLXSW_SP_PB(1, 0),
MLXSW_SP_PB(2, 0),
MLXSW_SP_PB(3, 0),
MLXSW_SP_PB(4, 0),
MLXSW_SP_PB(5, 0),
MLXSW_SP_PB(6, 0),
MLXSW_SP_PB(7, 0),
MLXSW_SP_PB(9, 2 * MLXSW_SP_BYTES_TO_CELLS(MLXSW_PORT_MAX_MTU)),
};
#define MLXSW_SP_PBS_LEN ARRAY_SIZE(mlxsw_sp_pbs)
......@@ -78,11 +80,33 @@ static int mlxsw_sp_port_pb_init(struct mlxsw_sp_port *mlxsw_sp_port)
pb = &mlxsw_sp_pbs[i];
mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl, pb->index, pb->size);
}
mlxsw_reg_pbmc_lossy_buffer_pack(pbmc_pl,
MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX, 0);
return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core,
MLXSW_REG(pbmc), pbmc_pl);
}
#define MLXSW_SP_SB_BYTES_PER_CELL 96
static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
char pptb_pl[MLXSW_REG_PPTB_LEN];
int i;
mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port);
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
mlxsw_reg_pptb_prio_to_buff_set(pptb_pl, i, 0);
return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb),
pptb_pl);
}
static int mlxsw_sp_port_headroom_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
int err;
err = mlxsw_sp_port_pb_init(mlxsw_sp_port);
if (err)
return err;
return mlxsw_sp_port_pb_prio_init(mlxsw_sp_port);
}
struct mlxsw_sp_sb_pool {
u8 pool;
......@@ -92,11 +116,9 @@ struct mlxsw_sp_sb_pool {
};
#define MLXSW_SP_SB_POOL_INGRESS_SIZE \
((15000000 - (2 * 20000 * MLXSW_PORT_MAX_PORTS)) / \
MLXSW_SP_SB_BYTES_PER_CELL)
(15000000 - (2 * 20000 * MLXSW_PORT_MAX_PORTS))
#define MLXSW_SP_SB_POOL_EGRESS_SIZE \
((14000000 - (8 * 1500 * MLXSW_PORT_MAX_PORTS)) / \
MLXSW_SP_SB_BYTES_PER_CELL)
(14000000 - (8 * 1500 * MLXSW_PORT_MAX_PORTS))
#define MLXSW_SP_SB_POOL(_pool, _dir, _mode, _size) \
{ \
......@@ -115,14 +137,14 @@ struct mlxsw_sp_sb_pool {
MLXSW_REG_SBPR_MODE_DYNAMIC, _size)
static const struct mlxsw_sp_sb_pool mlxsw_sp_sb_pools[] = {
MLXSW_SP_SB_POOL_INGRESS(0, MLXSW_SP_SB_POOL_INGRESS_SIZE),
MLXSW_SP_SB_POOL_INGRESS(0, MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_POOL_INGRESS_SIZE)),
MLXSW_SP_SB_POOL_INGRESS(1, 0),
MLXSW_SP_SB_POOL_INGRESS(2, 0),
MLXSW_SP_SB_POOL_INGRESS(3, 0),
MLXSW_SP_SB_POOL_EGRESS(0, MLXSW_SP_SB_POOL_EGRESS_SIZE),
MLXSW_SP_SB_POOL_EGRESS(0, MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_POOL_EGRESS_SIZE)),
MLXSW_SP_SB_POOL_EGRESS(1, 0),
MLXSW_SP_SB_POOL_EGRESS(2, 0),
MLXSW_SP_SB_POOL_EGRESS(2, MLXSW_SP_SB_POOL_EGRESS_SIZE),
MLXSW_SP_SB_POOL_EGRESS(2, MLXSW_SP_BYTES_TO_CELLS(MLXSW_SP_SB_POOL_EGRESS_SIZE)),
};
#define MLXSW_SP_SB_POOLS_LEN ARRAY_SIZE(mlxsw_sp_sb_pools)
......@@ -178,7 +200,7 @@ struct mlxsw_sp_sb_cm {
MLXSW_SP_SB_CM(_tc, MLXSW_REG_SBCM_DIR_EGRESS, 104, 2, 3)
static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms[] = {
MLXSW_SP_SB_CM_INGRESS(0, 10000 / MLXSW_SP_SB_BYTES_PER_CELL, 8),
MLXSW_SP_SB_CM_INGRESS(0, MLXSW_SP_BYTES_TO_CELLS(10000), 8),
MLXSW_SP_SB_CM_INGRESS(1, 0, 0),
MLXSW_SP_SB_CM_INGRESS(2, 0, 0),
MLXSW_SP_SB_CM_INGRESS(3, 0, 0),
......@@ -186,15 +208,15 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms[] = {
MLXSW_SP_SB_CM_INGRESS(5, 0, 0),
MLXSW_SP_SB_CM_INGRESS(6, 0, 0),
MLXSW_SP_SB_CM_INGRESS(7, 0, 0),
MLXSW_SP_SB_CM_INGRESS(9, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff),
MLXSW_SP_SB_CM_EGRESS(0, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(1, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(2, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(3, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(4, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(5, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(6, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_EGRESS(7, 1500 / MLXSW_SP_SB_BYTES_PER_CELL, 9),
MLXSW_SP_SB_CM_INGRESS(9, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff),
MLXSW_SP_SB_CM_EGRESS(0, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(1, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(2, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(3, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(4, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(5, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(6, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(7, MLXSW_SP_BYTES_TO_CELLS(1500), 9),
MLXSW_SP_SB_CM_EGRESS(8, 0, 0),
MLXSW_SP_SB_CM_EGRESS(9, 0, 0),
MLXSW_SP_SB_CM_EGRESS(10, 0, 0),
......@@ -353,21 +375,21 @@ struct mlxsw_sp_sb_mm {
}
static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
MLXSW_SP_SB_MM(0, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(1, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(2, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(3, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(4, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(5, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(6, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(7, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(8, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(9, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(10, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(11, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(12, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(13, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(14, 20000 / MLXSW_SP_SB_BYTES_PER_CELL, 0xff, 0),
MLXSW_SP_SB_MM(0, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(1, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(2, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(3, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(4, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(5, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(6, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(7, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(8, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(9, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(10, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(11, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(12, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(13, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
MLXSW_SP_SB_MM(14, MLXSW_SP_BYTES_TO_CELLS(20000), 0xff, 0),
};
#define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
......@@ -410,7 +432,7 @@ int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
int err;
err = mlxsw_sp_port_pb_init(mlxsw_sp_port);
err = mlxsw_sp_port_headroom_init(mlxsw_sp_port);
if (err)
return err;
err = mlxsw_sp_port_sb_cms_init(mlxsw_sp_port);
......
This diff is collapsed.
......@@ -518,7 +518,8 @@ static void mlxsw_sx_port_get_stats(struct net_device *dev,
int i;
int err;
mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sx_port->local_port);
mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sx_port->local_port,
MLXSW_REG_PPCNT_IEEE_8023_CNT, 0);
err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppcnt), ppcnt_pl);
for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++)
data[i] = !err ? mlxsw_sx_port_hw_stats[i].getter(ppcnt_pl) : 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment