Commit 90e05ef3 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-dsa-microchip-add-support-for-credit-based-shaper'

Arun Ramadoss says:

====================
net: dsa: microchip: add support for credit based shaper

LAN937x switch family, KSZ9477, KSZ9567, KSZ9563 and KSZ8563 supports
the credit based shaper. But there were few difference between LAN937x and KSZ
switch like
- number of queues for LAN937x is 8 and for others it is 4.
- size of credit increment register for LAN937x is 24 and for other is 16-bit.
This patch series add the credit based shaper with common implementation for
LAN937x and KSZ swithes.
====================

Link: https://lore.kernel.org/r/20230120052135.32120-1-arun.ramadoss@microchip.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3176eb82 71d7920f
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -980,6 +980,22 @@ int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
	return ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
}

void ksz9477_port_queue_split(struct ksz_device *dev, int port)
{
	u8 data;

	if (dev->info->num_tx_queues == 8)
		data = PORT_EIGHT_QUEUE;
	else if (dev->info->num_tx_queues == 4)
		data = PORT_FOUR_QUEUE;
	else if (dev->info->num_tx_queues == 2)
		data = PORT_TWO_QUEUE;
	else
		data = PORT_SINGLE_QUEUE;

	ksz_prmw8(dev, port, REG_PORT_CTRL_0, PORT_QUEUE_SPLIT_MASK, data);
}

void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
	struct dsa_switch *ds = dev->ds;
@@ -991,6 +1007,8 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
		ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE,
			     true);

	ksz9477_port_queue_split(dev, port);

	ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false);

	/* set back pressure */
@@ -1166,6 +1184,13 @@ u32 ksz9477_get_port_addr(int port, int offset)
	return PORT_CTRL_ADDR(port, offset);
}

int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
{
	val = val >> 8;

	return ksz_pwrite16(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);
}

int ksz9477_switch_init(struct ksz_device *dev)
{
	u8 data8;
+2 −0
Original line number Diff line number Diff line
@@ -51,10 +51,12 @@ int ksz9477_mdb_del(struct ksz_device *dev, int port,
		    const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu);
void ksz9477_config_cpu_port(struct dsa_switch *ds);
int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val);
int ksz9477_enable_stp_addr(struct ksz_device *dev);
int ksz9477_reset_switch(struct ksz_device *dev);
int ksz9477_dsa_init(struct ksz_device *dev);
int ksz9477_switch_init(struct ksz_device *dev);
void ksz9477_switch_exit(struct ksz_device *dev);
void ksz9477_port_queue_split(struct ksz_device *dev, int port);

#endif
+7 −26
Original line number Diff line number Diff line
@@ -850,7 +850,11 @@
#define PORT_FORCE_TX_FLOW_CTRL		BIT(4)
#define PORT_FORCE_RX_FLOW_CTRL		BIT(3)
#define PORT_TAIL_TAG_ENABLE		BIT(2)
#define PORT_QUEUE_SPLIT_ENABLE		0x3
#define PORT_QUEUE_SPLIT_MASK		GENMASK(1, 0)
#define PORT_EIGHT_QUEUE		0x3
#define PORT_FOUR_QUEUE			0x2
#define PORT_TWO_QUEUE			0x1
#define PORT_SINGLE_QUEUE		0x0

#define REG_PORT_CTRL_1			0x0021

@@ -1480,33 +1484,10 @@

/* 9 - Shaping */

#define REG_PORT_MTI_QUEUE_INDEX__4	0x0900

#define REG_PORT_MTI_QUEUE_CTRL_0__4   0x0904

#define MTI_PVID_REPLACE               BIT(0)

#define REG_PORT_MTI_QUEUE_CTRL_0	0x0914

#define MTI_SCHEDULE_MODE_M		0x3
#define MTI_SCHEDULE_MODE_S		6
#define MTI_SCHEDULE_STRICT_PRIO	0
#define MTI_SCHEDULE_WRR		2
#define MTI_SHAPING_M			0x3
#define MTI_SHAPING_S			4
#define MTI_SHAPING_OFF			0
#define MTI_SHAPING_SRP			1
#define MTI_SHAPING_TIME_AWARE		2

#define REG_PORT_MTI_QUEUE_CTRL_1	0x0915

#define MTI_TX_RATIO_M			(BIT(7) - 1)

#define REG_PORT_MTI_QUEUE_CTRL_2__2	0x0916
#define REG_PORT_MTI_HI_WATER_MARK	0x0916
#define REG_PORT_MTI_QUEUE_CTRL_3__2	0x0918
#define REG_PORT_MTI_LO_WATER_MARK	0x0918
#define REG_PORT_MTI_QUEUE_CTRL_4__2	0x091A
#define REG_PORT_MTI_CREDIT_INCREMENT	0x091A

/* A - QM */
+130 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/of_net.h>
#include <linux/micrel_phy.h>
#include <net/dsa.h>
#include <net/pkt_cls.h>
#include <net/switchdev.h>

#include "ksz_common.h"
@@ -31,6 +32,10 @@
#include "ksz9477.h"
#include "lan937x.h"

#define KSZ_CBS_ENABLE ((MTI_SCHEDULE_STRICT_PRIO << MTI_SCHEDULE_MODE_S) | \
			(MTI_SHAPING_SRP << MTI_SHAPING_S))
#define KSZ_CBS_DISABLE ((MTI_SCHEDULE_WRR << MTI_SCHEDULE_MODE_S) |\
			 (MTI_SHAPING_OFF << MTI_SHAPING_S))
#define MIB_COUNTER_NUM 0x20

struct ksz_stats_raw {
@@ -250,6 +255,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
	.change_mtu = ksz9477_change_mtu,
	.phylink_mac_link_up = ksz9477_phylink_mac_link_up,
	.config_cpu_port = ksz9477_config_cpu_port,
	.tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc,
	.enable_stp_addr = ksz9477_enable_stp_addr,
	.reset = ksz9477_reset_switch,
	.init = ksz9477_switch_init,
@@ -286,6 +292,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = {
	.change_mtu = lan937x_change_mtu,
	.phylink_mac_link_up = ksz9477_phylink_mac_link_up,
	.config_cpu_port = lan937x_config_cpu_port,
	.tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc,
	.enable_stp_addr = ksz9477_enable_stp_addr,
	.reset = lan937x_reset_switch,
	.init = lan937x_switch_init,
@@ -1080,6 +1087,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x07,	/* can be configured as cpu port */
		.port_cnt = 3,		/* total port count */
		.port_nirqs = 3,
		.num_tx_queues = 4,
		.tc_cbs_supported = true,
		.ops = &ksz9477_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1106,6 +1115,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.num_tx_queues = 4,
		.ops = &ksz8_dev_ops,
		.ksz87xx_eee_link_erratum = true,
		.mib_names = ksz9477_mib_names,
@@ -1144,6 +1154,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.num_tx_queues = 4,
		.ops = &ksz8_dev_ops,
		.ksz87xx_eee_link_erratum = true,
		.mib_names = ksz9477_mib_names,
@@ -1168,6 +1179,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.num_tx_queues = 4,
		.ops = &ksz8_dev_ops,
		.ksz87xx_eee_link_erratum = true,
		.mib_names = ksz9477_mib_names,
@@ -1192,6 +1204,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.num_statics = 8,
		.cpu_ports = 0x4,	/* can be configured as cpu port */
		.port_cnt = 3,
		.num_tx_queues = 4,
		.ops = &ksz8_dev_ops,
		.mib_names = ksz88xx_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
@@ -1213,6 +1226,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.port_nirqs = 4,
		.num_tx_queues = 4,
		.tc_cbs_supported = true,
		.ops = &ksz9477_dev_ops,
		.phy_errata_9477 = true,
		.mib_names = ksz9477_mib_names,
@@ -1245,6 +1260,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x3F,	/* can be configured as cpu port */
		.port_cnt = 6,		/* total physical port count */
		.port_nirqs = 2,
		.num_tx_queues = 4,
		.ops = &ksz9477_dev_ops,
		.phy_errata_9477 = true,
		.mib_names = ksz9477_mib_names,
@@ -1277,6 +1293,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.port_nirqs = 2,
		.num_tx_queues = 4,
		.ops = &ksz9477_dev_ops,
		.phy_errata_9477 = true,
		.mib_names = ksz9477_mib_names,
@@ -1307,6 +1324,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x07,	/* can be configured as cpu port */
		.port_cnt = 3,		/* total port count */
		.port_nirqs = 2,
		.num_tx_queues = 4,
		.ops = &ksz9477_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1332,6 +1350,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x07,	/* can be configured as cpu port */
		.port_cnt = 3,		/* total port count */
		.port_nirqs = 3,
		.num_tx_queues = 4,
		.tc_cbs_supported = true,
		.ops = &ksz9477_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1357,6 +1377,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.port_nirqs = 3,
		.num_tx_queues = 4,
		.tc_cbs_supported = true,
		.ops = &ksz9477_dev_ops,
		.phy_errata_9477 = true,
		.mib_names = ksz9477_mib_names,
@@ -1387,6 +1409,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total physical port count */
		.port_nirqs = 6,
		.num_tx_queues = 8,
		.tc_cbs_supported = true,
		.ops = &lan937x_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1411,6 +1435,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x30,	/* can be configured as cpu port */
		.port_cnt = 6,		/* total physical port count */
		.port_nirqs = 6,
		.num_tx_queues = 8,
		.tc_cbs_supported = true,
		.ops = &lan937x_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1435,6 +1461,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x30,	/* can be configured as cpu port */
		.port_cnt = 8,		/* total physical port count */
		.port_nirqs = 6,
		.num_tx_queues = 8,
		.tc_cbs_supported = true,
		.ops = &lan937x_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1463,6 +1491,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x38,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total physical port count */
		.port_nirqs = 6,
		.num_tx_queues = 8,
		.tc_cbs_supported = true,
		.ops = &lan937x_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -1491,6 +1521,8 @@ const struct ksz_chip_data ksz_switch_chips[] = {
		.cpu_ports = 0x30,	/* can be configured as cpu port */
		.port_cnt = 8,		/* total physical port count */
		.port_nirqs = 6,
		.num_tx_queues = 8,
		.tc_cbs_supported = true,
		.ops = &lan937x_dev_ops,
		.mib_names = ksz9477_mib_names,
		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
@@ -2065,6 +2097,8 @@ static int ksz_setup(struct dsa_switch *ds)

	dev->dev_ops->enable_stp_addr(dev);

	ds->num_tx_queues = dev->info->num_tx_queues;

	regmap_update_bits(dev->regmap[0], regs[S_MULTICAST_CTRL],
			   MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE);

@@ -2958,6 +2992,101 @@ static int ksz_switch_detect(struct ksz_device *dev)
	return 0;
}

/* Bandwidth is calculated by idle slope/transmission speed. Then the Bandwidth
 * is converted to Hex-decimal using the successive multiplication method. On
 * every step, integer part is taken and decimal part is carry forwarded.
 */
static int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw)
{
	u32 cinc = 0;
	u32 txrate;
	u32 rate;
	u8 temp;
	u8 i;

	txrate = idle_slope - send_slope;

	if (!txrate)
		return -EINVAL;

	rate = idle_slope;

	/* 24 bit register */
	for (i = 0; i < 6; i++) {
		rate = rate * 16;

		temp = rate / txrate;

		rate %= txrate;

		cinc = ((cinc << 4) | temp);
	}

	*bw = cinc;

	return 0;
}

static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,
			    struct tc_cbs_qopt_offload *qopt)
{
	struct ksz_device *dev = ds->priv;
	int ret;
	u32 bw;

	if (!dev->info->tc_cbs_supported)
		return -EOPNOTSUPP;

	if (qopt->queue > dev->info->num_tx_queues)
		return -EINVAL;

	/* Queue Selection */
	ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, qopt->queue);
	if (ret)
		return ret;

	if (!qopt->enable)
		return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
				   KSZ_CBS_DISABLE);

	/* High Credit */
	ret = ksz_pwrite16(dev, port, REG_PORT_MTI_HI_WATER_MARK,
			   qopt->hicredit);
	if (ret)
		return ret;

	/* Low Credit */
	ret = ksz_pwrite16(dev, port, REG_PORT_MTI_LO_WATER_MARK,
			   qopt->locredit);
	if (ret)
		return ret;

	/* Credit Increment Register */
	ret = cinc_cal(qopt->idleslope, qopt->sendslope, &bw);
	if (ret)
		return ret;

	if (dev->dev_ops->tc_cbs_set_cinc) {
		ret = dev->dev_ops->tc_cbs_set_cinc(dev, port, bw);
		if (ret)
			return ret;
	}

	return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0,
			   KSZ_CBS_ENABLE);
}

static int ksz_setup_tc(struct dsa_switch *ds, int port,
			enum tc_setup_type type, void *type_data)
{
	switch (type) {
	case TC_SETUP_QDISC_CBS:
		return ksz_setup_tc_cbs(ds, port, type_data);
	default:
		return -EOPNOTSUPP;
	}
}

static const struct dsa_switch_ops ksz_switch_ops = {
	.get_tag_protocol	= ksz_get_tag_protocol,
	.connect_tag_protocol   = ksz_connect_tag_protocol,
@@ -3000,6 +3129,7 @@ static const struct dsa_switch_ops ksz_switch_ops = {
	.port_hwtstamp_set	= ksz_hwtstamp_set,
	.port_txtstamp		= ksz_port_txtstamp,
	.port_rxtstamp		= ksz_port_rxtstamp,
	.port_setup_tc		= ksz_setup_tc,
};

struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
+21 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ struct ksz_chip_data {
	int cpu_ports;
	int port_cnt;
	u8 port_nirqs;
	u8 num_tx_queues;
	bool tc_cbs_supported;
	const struct ksz_dev_ops *ops;
	bool phy_errata_9477;
	bool ksz87xx_eee_link_erratum;
@@ -353,6 +355,7 @@ struct ksz_dev_ops {
				    struct phy_device *phydev, int speed,
				    int duplex, bool tx_pause, bool rx_pause);
	void (*setup_rgmii_delay)(struct ksz_device *dev, int port);
	int (*tc_cbs_set_cinc)(struct ksz_device *dev, int port, u32 val);
	void (*config_cpu_port)(struct dsa_switch *ds);
	int (*enable_stp_addr)(struct ksz_device *dev);
	int (*reset)(struct ksz_device *dev);
@@ -646,6 +649,24 @@ static inline int is_lan937x(struct ksz_device *dev)
#define KSZ8_LEGAL_PACKET_SIZE		1518
#define KSZ9477_MAX_FRAME_SIZE		9000

/* CBS related registers */
#define REG_PORT_MTI_QUEUE_INDEX__4	0x0900

#define REG_PORT_MTI_QUEUE_CTRL_0	0x0914

#define MTI_SCHEDULE_MODE_M		0x3
#define MTI_SCHEDULE_MODE_S		6
#define MTI_SCHEDULE_STRICT_PRIO	0
#define MTI_SCHEDULE_WRR		2
#define MTI_SHAPING_M			0x3
#define MTI_SHAPING_S			4
#define MTI_SHAPING_OFF			0
#define MTI_SHAPING_SRP			1
#define MTI_SHAPING_TIME_AWARE		2

#define REG_PORT_MTI_HI_WATER_MARK	0x0916
#define REG_PORT_MTI_LO_WATER_MARK	0x0918

/* Regmap tables generation */
#define KSZ_SPI_OP_RD		3
#define KSZ_SPI_OP_WR		2
Loading