Commit 5cd129dd authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-Small-driver-update'



Jiri Pirko says:

====================
mlxsw: Small driver update

This patchset contains couple of patches not related to each other. They
are small optimization and extension changes to the driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c535f920 3b909c55
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -621,7 +621,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload)
{
	MLXSW_REG_ZERO(sfn, payload);
	mlxsw_reg_sfn_swid_set(payload, 0);
	mlxsw_reg_sfn_end_set(payload, 1);
	mlxsw_reg_sfn_end_set(payload, 0);
	mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT);
}

+54 −80
Original line number Diff line number Diff line
@@ -2228,6 +2228,15 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_rfc_3635_stats[] = {
#define MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN \
	ARRAY_SIZE(mlxsw_sp_port_hw_rfc_3635_stats)

static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_ext_stats[] = {
	{
		.str = "ecn_marked",
		.getter = mlxsw_reg_ppcnt_ecn_marked_get,
	},
};

#define MLXSW_SP_PORT_HW_EXT_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_ext_stats)

static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_discard_stats[] = {
	{
		.str = "discard_ingress_general",
@@ -2337,6 +2346,7 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
					 MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \
					 MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \
					 MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN + \
					 MLXSW_SP_PORT_HW_EXT_STATS_LEN + \
					 MLXSW_SP_PORT_HW_DISCARD_STATS_LEN + \
					 (MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \
					  IEEE_8021QAZ_MAX_TCS) + \
@@ -2398,6 +2408,12 @@ static void mlxsw_sp_port_get_strings(struct net_device *dev,
			p += ETH_GSTRING_LEN;
		}

		for (i = 0; i < MLXSW_SP_PORT_HW_EXT_STATS_LEN; i++) {
			memcpy(p, mlxsw_sp_port_hw_ext_stats[i].str,
			       ETH_GSTRING_LEN);
			p += ETH_GSTRING_LEN;
		}

		for (i = 0; i < MLXSW_SP_PORT_HW_DISCARD_STATS_LEN; i++) {
			memcpy(p, mlxsw_sp_port_hw_discard_stats[i].str,
			       ETH_GSTRING_LEN);
@@ -2459,6 +2475,10 @@ mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
		*p_hw_stats = mlxsw_sp_port_hw_rfc_3635_stats;
		*p_len = MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;
		break;
	case MLXSW_REG_PPCNT_EXT_CNT:
		*p_hw_stats = mlxsw_sp_port_hw_ext_stats;
		*p_len = MLXSW_SP_PORT_HW_EXT_STATS_LEN;
		break;
	case MLXSW_REG_PPCNT_DISCARD_CNT:
		*p_hw_stats = mlxsw_sp_port_hw_discard_stats;
		*p_len = MLXSW_SP_PORT_HW_DISCARD_STATS_LEN;
@@ -2528,6 +2548,11 @@ static void mlxsw_sp_port_get_stats(struct net_device *dev,
				  data, data_index);
	data_index += MLXSW_SP_PORT_HW_RFC_3635_STATS_LEN;

	/* Extended Counters */
	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
				  data, data_index);
	data_index += MLXSW_SP_PORT_HW_EXT_STATS_LEN;

	/* Discard Counters */
	__mlxsw_sp_port_get_stats(dev, MLXSW_REG_PPCNT_DISCARD_CNT, 0,
				  data, data_index);
@@ -2773,27 +2798,6 @@ static u32 mlxsw_sp1_to_ptys_speed(struct mlxsw_sp *mlxsw_sp, u8 width,
	return ptys_proto;
}

static u32
mlxsw_sp1_to_ptys_upper_speed(struct mlxsw_sp *mlxsw_sp, u32 upper_speed)
{
	u32 ptys_proto = 0;
	int i;

	for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
		if (mlxsw_sp1_port_link_mode[i].speed <= upper_speed)
			ptys_proto |= mlxsw_sp1_port_link_mode[i].mask;
	}
	return ptys_proto;
}

static int
mlxsw_sp1_port_speed_base(struct mlxsw_sp *mlxsw_sp, u8 local_port,
			  u32 *base_speed)
{
	*base_speed = MLXSW_SP_PORT_BASE_SPEED_25G;
	return 0;
}

static void
mlxsw_sp1_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
			    u8 local_port, u32 proto_admin, bool autoneg)
@@ -2818,8 +2822,6 @@ mlxsw_sp1_port_type_speed_ops = {
	.from_ptys_speed_duplex		= mlxsw_sp1_from_ptys_speed_duplex,
	.to_ptys_advert_link		= mlxsw_sp1_to_ptys_advert_link,
	.to_ptys_speed			= mlxsw_sp1_to_ptys_speed,
	.to_ptys_upper_speed		= mlxsw_sp1_to_ptys_upper_speed,
	.port_speed_base		= mlxsw_sp1_port_speed_base,
	.reg_ptys_eth_pack		= mlxsw_sp1_reg_ptys_eth_pack,
	.reg_ptys_eth_unpack		= mlxsw_sp1_reg_ptys_eth_unpack,
};
@@ -3220,51 +3222,6 @@ static u32 mlxsw_sp2_to_ptys_speed(struct mlxsw_sp *mlxsw_sp,
	return ptys_proto;
}

static u32
mlxsw_sp2_to_ptys_upper_speed(struct mlxsw_sp *mlxsw_sp, u32 upper_speed)
{
	u32 ptys_proto = 0;
	int i;

	for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
		if (mlxsw_sp2_port_link_mode[i].speed <= upper_speed)
			ptys_proto |= mlxsw_sp2_port_link_mode[i].mask;
	}
	return ptys_proto;
}

static int
mlxsw_sp2_port_speed_base(struct mlxsw_sp *mlxsw_sp, u8 local_port,
			  u32 *base_speed)
{
	char ptys_pl[MLXSW_REG_PTYS_LEN];
	u32 eth_proto_cap;
	int err;

	/* In Spectrum-2, the speed of 1x can change from port to port, so query
	 * it from firmware.
	 */
	mlxsw_reg_ptys_ext_eth_pack(ptys_pl, local_port, 0, false);
	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
	if (err)
		return err;
	mlxsw_reg_ptys_ext_eth_unpack(ptys_pl, &eth_proto_cap, NULL, NULL);

	if (eth_proto_cap &
	    MLXSW_REG_PTYS_EXT_ETH_SPEED_50GAUI_1_LAUI_1_50GBASE_CR_KR) {
		*base_speed = MLXSW_SP_PORT_BASE_SPEED_50G;
		return 0;
	}

	if (eth_proto_cap &
	    MLXSW_REG_PTYS_EXT_ETH_SPEED_25GAUI_1_25GBASE_CR_KR) {
		*base_speed = MLXSW_SP_PORT_BASE_SPEED_25G;
		return 0;
	}

	return -EIO;
}

static void
mlxsw_sp2_reg_ptys_eth_pack(struct mlxsw_sp *mlxsw_sp, char *payload,
			    u8 local_port, u32 proto_admin,
@@ -3290,8 +3247,6 @@ mlxsw_sp2_port_type_speed_ops = {
	.from_ptys_speed_duplex		= mlxsw_sp2_from_ptys_speed_duplex,
	.to_ptys_advert_link		= mlxsw_sp2_to_ptys_advert_link,
	.to_ptys_speed			= mlxsw_sp2_to_ptys_speed,
	.to_ptys_upper_speed		= mlxsw_sp2_to_ptys_upper_speed,
	.port_speed_base		= mlxsw_sp2_port_speed_base,
	.reg_ptys_eth_pack		= mlxsw_sp2_reg_ptys_eth_pack,
	.reg_ptys_eth_unpack		= mlxsw_sp2_reg_ptys_eth_unpack,
};
@@ -3505,24 +3460,24 @@ static int
mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
	const struct mlxsw_sp_port_type_speed_ops *ops;
	char ptys_pl[MLXSW_REG_PTYS_LEN];
	u32 eth_proto_admin;
	u32 upper_speed;
	u32 base_speed;
	int err;

	ops = mlxsw_sp->port_type_speed_ops;

	err = ops->port_speed_base(mlxsw_sp, mlxsw_sp_port->local_port,
				   &base_speed);
	/* Set advertised speeds to supported speeds. */
	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
			       0, false);
	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
	if (err)
		return err;
	upper_speed = base_speed * mlxsw_sp_port->mapping.width;

	eth_proto_admin = ops->to_ptys_upper_speed(mlxsw_sp, upper_speed);
	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap,
				 &eth_proto_admin, &eth_proto_oper);
	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
			       eth_proto_admin, mlxsw_sp_port->link.autoneg);
			       eth_proto_cap, mlxsw_sp_port->link.autoneg);
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
}

@@ -4920,16 +4875,35 @@ static const struct mlxsw_sp_span_ops mlxsw_sp1_span_ops = {
};

#define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38
#define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50

static u32 __mlxsw_sp_span_buffsize_get(int mtu, u32 speed, u32 buffer_factor)
{
	return 3 * mtu + buffer_factor * speed / 1000;
}

static u32 mlxsw_sp2_span_buffsize_get(int mtu, u32 speed)
{
	return 3 * mtu + MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR * speed / 1000;
	int factor = MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR;

	return __mlxsw_sp_span_buffsize_get(mtu, speed, factor);
}

static const struct mlxsw_sp_span_ops mlxsw_sp2_span_ops = {
	.buffsize_get = mlxsw_sp2_span_buffsize_get,
};

static u32 mlxsw_sp3_span_buffsize_get(int mtu, u32 speed)
{
	int factor = MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR;

	return __mlxsw_sp_span_buffsize_get(mtu, speed, factor);
}

static const struct mlxsw_sp_span_ops mlxsw_sp3_span_ops = {
	.buffsize_get = mlxsw_sp3_span_buffsize_get,
};

u32 mlxsw_sp_span_buffsize_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed)
{
	u32 buffsize = mlxsw_sp->span_ops->buffsize_get(speed, mtu);
@@ -5208,7 +5182,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
	mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
	mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;
	mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;

	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
+0 −6
Original line number Diff line number Diff line
@@ -33,9 +33,6 @@

#define MLXSW_SP_MID_MAX 7000

#define MLXSW_SP_PORT_BASE_SPEED_25G 25000 /* Mb/s */
#define MLXSW_SP_PORT_BASE_SPEED_50G 50000 /* Mb/s */

#define MLXSW_SP_KVD_LINEAR_SIZE 98304 /* entries */
#define MLXSW_SP_KVD_GRANULARITY 128

@@ -310,9 +307,6 @@ struct mlxsw_sp_port_type_speed_ops {
	u32 (*to_ptys_advert_link)(struct mlxsw_sp *mlxsw_sp, u8 width,
				   const struct ethtool_link_ksettings *cmd);
	u32 (*to_ptys_speed)(struct mlxsw_sp *mlxsw_sp, u8 width, u32 speed);
	u32 (*to_ptys_upper_speed)(struct mlxsw_sp *mlxsw_sp, u32 upper_speed);
	int (*port_speed_base)(struct mlxsw_sp *mlxsw_sp, u8 local_port,
			       u32 *base_speed);
	void (*reg_ptys_eth_pack)(struct mlxsw_sp *mlxsw_sp, char *payload,
				  u8 local_port, u32 proto_admin, bool autoneg);
	void (*reg_ptys_eth_unpack)(struct mlxsw_sp *mlxsw_sp, char *payload,
+2 −7
Original line number Diff line number Diff line
@@ -347,7 +347,6 @@ mlxsw_sp_setup_tc_qdisc_red_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
					       mlxsw_sp_qdisc->prio_bitmap,
					       &stats_base->tx_packets,
					       &stats_base->tx_bytes);
	red_base->prob_mark = xstats->ecn;
	red_base->prob_drop = xstats->wred_drop[tclass_num];
	red_base->pdrop = mlxsw_sp_xstats_tail_drop(xstats, tclass_num);

@@ -453,22 +452,19 @@ mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
	u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
	struct mlxsw_sp_port_xstats *xstats;
	struct red_stats *res = xstats_ptr;
	int early_drops, marks, pdrops;
	int early_drops, pdrops;

	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;

	early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
	marks = xstats->ecn - xstats_base->prob_mark;
	pdrops = mlxsw_sp_xstats_tail_drop(xstats, tclass_num) -
		 xstats_base->pdrop;

	res->pdrop += pdrops;
	res->prob_drop += early_drops;
	res->prob_mark += marks;

	xstats_base->pdrop += pdrops;
	xstats_base->prob_drop += early_drops;
	xstats_base->prob_mark += marks;
	return 0;
}

@@ -486,8 +482,7 @@ mlxsw_sp_qdisc_get_red_stats(struct mlxsw_sp_port *mlxsw_sp_port,
	stats_base = &mlxsw_sp_qdisc->stats_base;

	mlxsw_sp_qdisc_get_tc_stats(mlxsw_sp_port, mlxsw_sp_qdisc, stats_ptr);
	overlimits = xstats->wred_drop[tclass_num] + xstats->ecn -
		     stats_base->overlimits;
	overlimits = xstats->wred_drop[tclass_num] - stats_base->overlimits;

	stats_ptr->qstats->overlimits += overlimits;
	stats_base->overlimits += overlimits;
+23 −12
Original line number Diff line number Diff line
@@ -2674,19 +2674,24 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
	}
}

static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp)
static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp,
					      bool no_delay)
{
	struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
	unsigned int interval = no_delay ? 0 : bridge->fdb_notify.interval;

	mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
			       msecs_to_jiffies(bridge->fdb_notify.interval));
			       msecs_to_jiffies(interval));
}

#define MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION 10

static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
{
	struct mlxsw_sp_bridge *bridge;
	struct mlxsw_sp *mlxsw_sp;
	char *sfn_pl;
	int queries;
	u8 num_rec;
	int i;
	int err;
@@ -2699,6 +2704,8 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
	mlxsw_sp = bridge->mlxsw_sp;

	rtnl_lock();
	queries = MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION;
	while (queries > 0) {
		mlxsw_reg_sfn_pack(sfn_pl);
		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
		if (err) {
@@ -2708,11 +2715,15 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
		num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
		for (i = 0; i < num_rec; i++)
			mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
		if (num_rec != MLXSW_REG_SFN_REC_MAX_COUNT)
			goto out;
		queries--;
	}

out:
	rtnl_unlock();
	kfree(sfn_pl);
	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, !queries);
}

struct mlxsw_sp_switchdev_event_work {
@@ -3458,7 +3469,7 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)

	INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
	bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, false);
	return 0;

err_register_switchdev_blocking_notifier: