diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/net/dsa/microchip | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/net/dsa/microchip')
| -rw-r--r-- | drivers/net/dsa/microchip/ksz8.h | 8 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz8795.c | 192 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz8863_smi.c | 9 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz9477_i2c.c | 2 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz_common.c | 254 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz_common.h | 18 | 
6 files changed, 379 insertions, 104 deletions
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h index ea05abfbd51d..e68465fdf6b9 100644 --- a/drivers/net/dsa/microchip/ksz8.h +++ b/drivers/net/dsa/microchip/ksz8.h @@ -21,10 +21,6 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);  int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val);  int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,  			 u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries); -int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, -			 struct alu_struct *alu); -void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr, -			  struct alu_struct *alu);  void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);  void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,  		    u64 *dropped, u64 *cnt); @@ -32,6 +28,10 @@ void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze);  void ksz8_port_init_cnt(struct ksz_device *dev, int port);  int ksz8_fdb_dump(struct ksz_device *dev, int port,  		  dsa_fdb_dump_cb_t *cb, void *data); +int ksz8_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr, +		 u16 vid, struct dsa_db db); +int ksz8_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr, +		 u16 vid, struct dsa_db db);  int ksz8_mdb_add(struct ksz_device *dev, int port,  		 const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);  int ksz8_mdb_del(struct ksz_device *dev, int port, diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 003b0ac2854c..f56fca1b1a22 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -96,7 +96,7 @@ static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size)  	if (frame_size > KSZ8_LEGAL_PACKET_SIZE)  		ctrl2 |= SW_LEGAL_PACKET_DISABLE; -	else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) +	if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)  		ctrl1 |= SW_HUGE_PACKET;  	ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1); @@ -336,34 +336,48 @@ void ksz8_port_init_cnt(struct ksz_device *dev, int port)  	}  } -static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data) +static int ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)  {  	const u16 *regs;  	u16 ctrl_addr; +	int ret;  	regs = dev->info->regs;  	ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;  	mutex_lock(&dev->alu_mutex); -	ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr); -	ksz_read64(dev, regs[REG_IND_DATA_HI], data); +	ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr); +	if (ret) +		goto unlock_alu; + +	ret = ksz_read64(dev, regs[REG_IND_DATA_HI], data); +unlock_alu:  	mutex_unlock(&dev->alu_mutex); + +	return ret;  } -static void ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data) +static int ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)  {  	const u16 *regs;  	u16 ctrl_addr; +	int ret;  	regs = dev->info->regs;  	ctrl_addr = IND_ACC_TABLE(table) | addr;  	mutex_lock(&dev->alu_mutex); -	ksz_write64(dev, regs[REG_IND_DATA_HI], data); -	ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr); +	ret = ksz_write64(dev, regs[REG_IND_DATA_HI], data); +	if (ret) +		goto unlock_alu; + +	ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr); +unlock_alu:  	mutex_unlock(&dev->alu_mutex); + +	return ret;  }  static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data) @@ -457,46 +471,54 @@ int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,  	return rc;  } -int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, -			 struct alu_struct *alu) +static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, +				struct alu_struct *alu, bool *valid)  {  	u32 data_hi, data_lo;  	const u8 *shifts;  	const u32 *masks;  	u64 data; +	int ret;  	shifts = dev->info->shifts;  	masks = dev->info->masks; -	ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data); +	ret = ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data); +	if (ret) +		return ret; +  	data_hi = data >> 32;  	data_lo = (u32)data; -	if (data_hi & (masks[STATIC_MAC_TABLE_VALID] | -			masks[STATIC_MAC_TABLE_OVERRIDE])) { -		alu->mac[5] = (u8)data_lo; -		alu->mac[4] = (u8)(data_lo >> 8); -		alu->mac[3] = (u8)(data_lo >> 16); -		alu->mac[2] = (u8)(data_lo >> 24); -		alu->mac[1] = (u8)data_hi; -		alu->mac[0] = (u8)(data_hi >> 8); -		alu->port_forward = -			(data_hi & masks[STATIC_MAC_TABLE_FWD_PORTS]) >> -				shifts[STATIC_MAC_FWD_PORTS]; -		alu->is_override = -			(data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0; -		data_hi >>= 1; -		alu->is_static = true; -		alu->is_use_fid = -			(data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0; -		alu->fid = (data_hi & masks[STATIC_MAC_TABLE_FID]) >> -				shifts[STATIC_MAC_FID]; + +	if (!(data_hi & (masks[STATIC_MAC_TABLE_VALID] | +			 masks[STATIC_MAC_TABLE_OVERRIDE]))) { +		*valid = false;  		return 0;  	} -	return -ENXIO; + +	alu->mac[5] = (u8)data_lo; +	alu->mac[4] = (u8)(data_lo >> 8); +	alu->mac[3] = (u8)(data_lo >> 16); +	alu->mac[2] = (u8)(data_lo >> 24); +	alu->mac[1] = (u8)data_hi; +	alu->mac[0] = (u8)(data_hi >> 8); +	alu->port_forward = +		(data_hi & masks[STATIC_MAC_TABLE_FWD_PORTS]) >> +			shifts[STATIC_MAC_FWD_PORTS]; +	alu->is_override = (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0; +	data_hi >>= 1; +	alu->is_static = true; +	alu->is_use_fid = (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0; +	alu->fid = (data_hi & masks[STATIC_MAC_TABLE_FID]) >> +		shifts[STATIC_MAC_FID]; + +	*valid = true; + +	return 0;  } -void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr, -			  struct alu_struct *alu) +static int ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr, +				struct alu_struct *alu)  {  	u32 data_hi, data_lo;  	const u8 *shifts; @@ -524,7 +546,8 @@ void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,  		data_hi &= ~masks[STATIC_MAC_TABLE_OVERRIDE];  	data = (u64)data_hi << 32 | data_lo; -	ksz8_w_table(dev, TABLE_STATIC_MAC, addr, data); + +	return ksz8_w_table(dev, TABLE_STATIC_MAC, addr, data);  }  static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid, @@ -958,15 +981,14 @@ int ksz8_fdb_dump(struct ksz_device *dev, int port,  	u16 entries = 0;  	u8 timestamp = 0;  	u8 fid; -	u8 member; -	struct alu_struct alu; +	u8 src_port; +	u8 mac[ETH_ALEN];  	do { -		alu.is_static = false; -		ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member, +		ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,  					   ×tamp, &entries); -		if (!ret && (member & BIT(port))) { -			ret = cb(alu.mac, alu.fid, alu.is_static, data); +		if (!ret && port == src_port) { +			ret = cb(mac, fid, false, data);  			if (ret)  				break;  		} @@ -978,24 +1000,29 @@ int ksz8_fdb_dump(struct ksz_device *dev, int port,  	return ret;  } -int ksz8_mdb_add(struct ksz_device *dev, int port, -		 const struct switchdev_obj_port_mdb *mdb, struct dsa_db db) +static int ksz8_add_sta_mac(struct ksz_device *dev, int port, +			    const unsigned char *addr, u16 vid)  {  	struct alu_struct alu; -	int index; +	int index, ret;  	int empty = 0;  	alu.port_forward = 0;  	for (index = 0; index < dev->info->num_statics; index++) { -		if (!ksz8_r_sta_mac_table(dev, index, &alu)) { -			/* Found one already in static MAC table. */ -			if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && -			    alu.fid == mdb->vid) -				break; -		/* Remember the first empty entry. */ -		} else if (!empty) { -			empty = index + 1; +		bool valid; + +		ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid); +		if (ret) +			return ret; +		if (!valid) { +			/* Remember the first empty entry. */ +			if (!empty) +				empty = index + 1; +			continue;  		} + +		if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid) +			break;  	}  	/* no available entry */ @@ -1006,48 +1033,73 @@ int ksz8_mdb_add(struct ksz_device *dev, int port,  	if (index == dev->info->num_statics) {  		index = empty - 1;  		memset(&alu, 0, sizeof(alu)); -		memcpy(alu.mac, mdb->addr, ETH_ALEN); +		memcpy(alu.mac, addr, ETH_ALEN);  		alu.is_static = true;  	}  	alu.port_forward |= BIT(port); -	if (mdb->vid) { +	if (vid) {  		alu.is_use_fid = true;  		/* Need a way to map VID to FID. */ -		alu.fid = mdb->vid; +		alu.fid = vid;  	} -	ksz8_w_sta_mac_table(dev, index, &alu); -	return 0; +	return ksz8_w_sta_mac_table(dev, index, &alu);  } -int ksz8_mdb_del(struct ksz_device *dev, int port, -		 const struct switchdev_obj_port_mdb *mdb, struct dsa_db db) +static int ksz8_del_sta_mac(struct ksz_device *dev, int port, +			    const unsigned char *addr, u16 vid)  {  	struct alu_struct alu; -	int index; +	int index, ret;  	for (index = 0; index < dev->info->num_statics; index++) { -		if (!ksz8_r_sta_mac_table(dev, index, &alu)) { -			/* Found one already in static MAC table. */ -			if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) && -			    alu.fid == mdb->vid) -				break; -		} +		bool valid; + +		ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid); +		if (ret) +			return ret; +		if (!valid) +			continue; + +		if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid) +			break;  	}  	/* no available entry */  	if (index == dev->info->num_statics) -		goto exit; +		return 0;  	/* clear port */  	alu.port_forward &= ~BIT(port);  	if (!alu.port_forward)  		alu.is_static = false; -	ksz8_w_sta_mac_table(dev, index, &alu); -exit: -	return 0; +	return ksz8_w_sta_mac_table(dev, index, &alu); +} + +int ksz8_mdb_add(struct ksz_device *dev, int port, +		 const struct switchdev_obj_port_mdb *mdb, struct dsa_db db) +{ +	return ksz8_add_sta_mac(dev, port, mdb->addr, mdb->vid); +} + +int ksz8_mdb_del(struct ksz_device *dev, int port, +		 const struct switchdev_obj_port_mdb *mdb, struct dsa_db db) +{ +	return ksz8_del_sta_mac(dev, port, mdb->addr, mdb->vid); +} + +int ksz8_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr, +		 u16 vid, struct dsa_db db) +{ +	return ksz8_add_sta_mac(dev, port, addr, vid); +} + +int ksz8_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr, +		 u16 vid, struct dsa_db db) +{ +	return ksz8_del_sta_mac(dev, port, addr, vid);  }  int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag, @@ -1347,9 +1399,7 @@ int ksz8_enable_stp_addr(struct ksz_device *dev)  	alu.is_override = true;  	alu.port_forward = dev->info->cpu_ports; -	ksz8_w_sta_mac_table(dev, 0, &alu); - -	return 0; +	return ksz8_w_sta_mac_table(dev, 0, &alu);  }  int ksz8_setup(struct dsa_switch *ds) diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index 2f4623f3bd85..3698112138b7 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -82,22 +82,16 @@ static const struct regmap_bus regmap_smi[] = {  	{  		.read = ksz8863_mdio_read,  		.write = ksz8863_mdio_write, -		.max_raw_read = 1, -		.max_raw_write = 1,  	},  	{  		.read = ksz8863_mdio_read,  		.write = ksz8863_mdio_write,  		.val_format_endian_default = REGMAP_ENDIAN_BIG, -		.max_raw_read = 2, -		.max_raw_write = 2,  	},  	{  		.read = ksz8863_mdio_read,  		.write = ksz8863_mdio_write,  		.val_format_endian_default = REGMAP_ENDIAN_BIG, -		.max_raw_read = 4, -		.max_raw_write = 4,  	}  }; @@ -108,7 +102,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {  		.pad_bits = 24,  		.val_bits = 8,  		.cache_type = REGCACHE_NONE, -		.use_single_read = 1,  		.lock = ksz_regmap_lock,  		.unlock = ksz_regmap_unlock,  	}, @@ -118,7 +111,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {  		.pad_bits = 24,  		.val_bits = 16,  		.cache_type = REGCACHE_NONE, -		.use_single_read = 1,  		.lock = ksz_regmap_lock,  		.unlock = ksz_regmap_unlock,  	}, @@ -128,7 +120,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {  		.pad_bits = 24,  		.val_bits = 32,  		.cache_type = REGCACHE_NONE, -		.use_single_read = 1,  		.lock = ksz_regmap_lock,  		.unlock = ksz_regmap_unlock,  	} diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index e315f669ec06..97a317263a2f 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);  static struct i2c_driver ksz9477_i2c_driver = {  	.driver = {  		.name	= "ksz9477-switch", -		.of_match_table = of_match_ptr(ksz9477_dt_ids), +		.of_match_table = ksz9477_dt_ids,  	},  	.probe_new = ksz9477_i2c_probe,  	.remove	= ksz9477_i2c_remove, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 729b36eeb2c4..a4428be5f483 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -32,10 +32,6 @@  #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 { @@ -204,6 +200,8 @@ static const struct ksz_dev_ops ksz8_dev_ops = {  	.freeze_mib = ksz8_freeze_mib,  	.port_init_cnt = ksz8_port_init_cnt,  	.fdb_dump = ksz8_fdb_dump, +	.fdb_add = ksz8_fdb_add, +	.fdb_del = ksz8_fdb_del,  	.mdb_add = ksz8_mdb_add,  	.mdb_del = ksz8_mdb_del,  	.vlan_filtering = ksz8_port_vlan_filtering, @@ -319,7 +317,7 @@ static const u16 ksz8795_regs[] = {  	[S_BROADCAST_CTRL]		= 0x06,  	[S_MULTICAST_CTRL]		= 0x04,  	[P_XMII_CTRL_0]			= 0x06, -	[P_XMII_CTRL_1]			= 0x56, +	[P_XMII_CTRL_1]			= 0x06,  };  static const u32 ksz8795_masks[] = { @@ -404,13 +402,13 @@ static const u32 ksz8863_masks[] = {  	[VLAN_TABLE_VALID]		= BIT(19),  	[STATIC_MAC_TABLE_VALID]	= BIT(19),  	[STATIC_MAC_TABLE_USE_FID]	= BIT(21), -	[STATIC_MAC_TABLE_FID]		= GENMASK(29, 26), +	[STATIC_MAC_TABLE_FID]		= GENMASK(25, 22),  	[STATIC_MAC_TABLE_OVERRIDE]	= BIT(20),  	[STATIC_MAC_TABLE_FWD_PORTS]	= GENMASK(18, 16), -	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(5, 0), -	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(7), +	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(1, 0), +	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(2),  	[DYNAMIC_MAC_TABLE_NOT_READY]	= BIT(7), -	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 28), +	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 24),  	[DYNAMIC_MAC_TABLE_FID]		= GENMASK(19, 16),  	[DYNAMIC_MAC_TABLE_SRC_PORT]	= GENMASK(21, 20),  	[DYNAMIC_MAC_TABLE_TIMESTAMP]	= GENMASK(23, 22), @@ -420,10 +418,10 @@ static u8 ksz8863_shifts[] = {  	[VLAN_TABLE_MEMBERSHIP_S]	= 16,  	[STATIC_MAC_FWD_PORTS]		= 16,  	[STATIC_MAC_FID]		= 22, -	[DYNAMIC_MAC_ENTRIES_H]		= 3, +	[DYNAMIC_MAC_ENTRIES_H]		= 8,  	[DYNAMIC_MAC_ENTRIES]		= 24,  	[DYNAMIC_MAC_FID]		= 16, -	[DYNAMIC_MAC_TIMESTAMP]		= 24, +	[DYNAMIC_MAC_TIMESTAMP]		= 22,  	[DYNAMIC_MAC_SRC_PORT]		= 20,  }; @@ -1089,6 +1087,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 3,  		.num_tx_queues = 4,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &ksz9477_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1228,6 +1227,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 4,  		.num_tx_queues = 4,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &ksz9477_dev_ops,  		.phy_errata_9477 = true,  		.mib_names = ksz9477_mib_names, @@ -1352,6 +1352,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 3,  		.num_tx_queues = 4,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &ksz9477_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1379,6 +1380,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 3,  		.num_tx_queues = 4,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &ksz9477_dev_ops,  		.phy_errata_9477 = true,  		.mib_names = ksz9477_mib_names, @@ -1411,6 +1413,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 6,  		.num_tx_queues = 8,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &lan937x_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1437,6 +1440,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 6,  		.num_tx_queues = 8,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &lan937x_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1463,6 +1467,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 6,  		.num_tx_queues = 8,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &lan937x_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1493,6 +1498,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 6,  		.num_tx_queues = 8,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &lan937x_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1523,6 +1529,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {  		.port_nirqs = 6,  		.num_tx_queues = 8,  		.tc_cbs_supported = true, +		.tc_ets_supported = true,  		.ops = &lan937x_dev_ops,  		.mib_names = ksz9477_mib_names,  		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -3091,6 +3098,14 @@ static int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw)  	return 0;  } +static int ksz_setup_tc_mode(struct ksz_device *dev, int port, u8 scheduler, +			     u8 shaper) +{ +	return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0, +			   FIELD_PREP(MTI_SCHEDULE_MODE_M, scheduler) | +			   FIELD_PREP(MTI_SHAPING_M, shaper)); +} +  static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,  			    struct tc_cbs_qopt_offload *qopt)  { @@ -3110,8 +3125,8 @@ static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,  		return ret;  	if (!qopt->enable) -		return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0, -				   KSZ_CBS_DISABLE); +		return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR, +					 MTI_SHAPING_OFF);  	/* High Credit */  	ret = ksz_pwrite16(dev, port, REG_PORT_MTI_HI_WATER_MARK, @@ -3136,8 +3151,215 @@ static int ksz_setup_tc_cbs(struct dsa_switch *ds, int port,  			return ret;  	} -	return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0, -			   KSZ_CBS_ENABLE); +	return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO, +				 MTI_SHAPING_SRP); +} + +static int ksz_disable_egress_rate_limit(struct ksz_device *dev, int port) +{ +	int queue, ret; + +	/* Configuration will not take effect until the last Port Queue X +	 * Egress Limit Control Register is written. +	 */ +	for (queue = 0; queue < dev->info->num_tx_queues; queue++) { +		ret = ksz_pwrite8(dev, port, KSZ9477_REG_PORT_OUT_RATE_0 + queue, +				  KSZ9477_OUT_RATE_NO_LIMIT); +		if (ret) +			return ret; +	} + +	return 0; +} + +static int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p, +				 int band) +{ +	/* Compared to queues, bands prioritize packets differently. In strict +	 * priority mode, the lowest priority is assigned to Queue 0 while the +	 * highest priority is given to Band 0. +	 */ +	return p->bands - 1 - band; +} + +static int ksz_queue_set_strict(struct ksz_device *dev, int port, int queue) +{ +	int ret; + +	ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue); +	if (ret) +		return ret; + +	return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO, +				 MTI_SHAPING_OFF); +} + +static int ksz_queue_set_wrr(struct ksz_device *dev, int port, int queue, +			     int weight) +{ +	int ret; + +	ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue); +	if (ret) +		return ret; + +	ret = ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR, +				MTI_SHAPING_OFF); +	if (ret) +		return ret; + +	return ksz_pwrite8(dev, port, KSZ9477_PORT_MTI_QUEUE_CTRL_1, weight); +} + +static int ksz_tc_ets_add(struct ksz_device *dev, int port, +			  struct tc_ets_qopt_offload_replace_params *p) +{ +	int ret, band, tc_prio; +	u32 queue_map = 0; + +	/* In order to ensure proper prioritization, it is necessary to set the +	 * rate limit for the related queue to zero. Otherwise strict priority +	 * or WRR mode will not work. This is a hardware limitation. +	 */ +	ret = ksz_disable_egress_rate_limit(dev, port); +	if (ret) +		return ret; + +	/* Configure queue scheduling mode for all bands. Currently only strict +	 * prio mode is supported. +	 */ +	for (band = 0; band < p->bands; band++) { +		int queue = ksz_ets_band_to_queue(p, band); + +		ret = ksz_queue_set_strict(dev, port, queue); +		if (ret) +			return ret; +	} + +	/* Configure the mapping between traffic classes and queues. Note: +	 * priomap variable support 16 traffic classes, but the chip can handle +	 * only 8 classes. +	 */ +	for (tc_prio = 0; tc_prio < ARRAY_SIZE(p->priomap); tc_prio++) { +		int queue; + +		if (tc_prio > KSZ9477_MAX_TC_PRIO) +			break; + +		queue = ksz_ets_band_to_queue(p, p->priomap[tc_prio]); +		queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S); +	} + +	return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map); +} + +static int ksz_tc_ets_del(struct ksz_device *dev, int port) +{ +	int ret, queue, tc_prio, s; +	u32 queue_map = 0; + +	/* To restore the default chip configuration, set all queues to use the +	 * WRR scheduler with a weight of 1. +	 */ +	for (queue = 0; queue < dev->info->num_tx_queues; queue++) { +		ret = ksz_queue_set_wrr(dev, port, queue, +					KSZ9477_DEFAULT_WRR_WEIGHT); +		if (ret) +			return ret; +	} + +	switch (dev->info->num_tx_queues) { +	case 2: +		s = 2; +		break; +	case 4: +		s = 1; +		break; +	case 8: +		s = 0; +		break; +	default: +		return -EINVAL; +	} + +	/* Revert the queue mapping for TC-priority to its default setting on +	 * the chip. +	 */ +	for (tc_prio = 0; tc_prio <= KSZ9477_MAX_TC_PRIO; tc_prio++) { +		int queue; + +		queue = tc_prio >> s; +		queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S); +	} + +	return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map); +} + +static int ksz_tc_ets_validate(struct ksz_device *dev, int port, +			       struct tc_ets_qopt_offload_replace_params *p) +{ +	int band; + +	/* Since it is not feasible to share one port among multiple qdisc, +	 * the user must configure all available queues appropriately. +	 */ +	if (p->bands != dev->info->num_tx_queues) { +		dev_err(dev->dev, "Not supported amount of bands. It should be %d\n", +			dev->info->num_tx_queues); +		return -EOPNOTSUPP; +	} + +	for (band = 0; band < p->bands; ++band) { +		/* The KSZ switches utilize a weighted round robin configuration +		 * where a certain number of packets can be transmitted from a +		 * queue before the next queue is serviced. For more information +		 * on this, refer to section 5.2.8.4 of the KSZ8565R +		 * documentation on the Port Transmit Queue Control 1 Register. +		 * However, the current ETS Qdisc implementation (as of February +		 * 2023) assigns a weight to each queue based on the number of +		 * bytes or extrapolated bandwidth in percentages. Since this +		 * differs from the KSZ switches' method and we don't want to +		 * fake support by converting bytes to packets, it is better to +		 * return an error instead. +		 */ +		if (p->quanta[band]) { +			dev_err(dev->dev, "Quanta/weights configuration is not supported.\n"); +			return -EOPNOTSUPP; +		} +	} + +	return 0; +} + +static int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port, +				  struct tc_ets_qopt_offload *qopt) +{ +	struct ksz_device *dev = ds->priv; +	int ret; + +	if (!dev->info->tc_ets_supported) +		return -EOPNOTSUPP; + +	if (qopt->parent != TC_H_ROOT) { +		dev_err(dev->dev, "Parent should be \"root\"\n"); +		return -EOPNOTSUPP; +	} + +	switch (qopt->command) { +	case TC_ETS_REPLACE: +		ret = ksz_tc_ets_validate(dev, port, &qopt->replace_params); +		if (ret) +			return ret; + +		return ksz_tc_ets_add(dev, port, &qopt->replace_params); +	case TC_ETS_DESTROY: +		return ksz_tc_ets_del(dev, port); +	case TC_ETS_STATS: +	case TC_ETS_GRAFT: +		return -EOPNOTSUPP; +	} + +	return -EOPNOTSUPP;  }  static int ksz_setup_tc(struct dsa_switch *ds, int port, @@ -3146,6 +3368,8 @@ static int ksz_setup_tc(struct dsa_switch *ds, int port,  	switch (type) {  	case TC_SETUP_QDISC_CBS:  		return ksz_setup_tc_cbs(ds, port, type_data); +	case TC_SETUP_QDISC_ETS: +		return ksz_tc_setup_qdisc_ets(ds, port, type_data);  	default:  		return -EOPNOTSUPP;  	} diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index d2d5761d58e9..8abecaf6089e 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -51,6 +51,7 @@ struct ksz_chip_data {  	u8 port_nirqs;  	u8 num_tx_queues;  	bool tc_cbs_supported; +	bool tc_ets_supported;  	const struct ksz_dev_ops *ops;  	bool phy_errata_9477;  	bool ksz87xx_eee_link_erratum; @@ -649,21 +650,30 @@ static inline int is_lan937x(struct ksz_device *dev)  #define KSZ8_LEGAL_PACKET_SIZE		1518  #define KSZ9477_MAX_FRAME_SIZE		9000 +#define KSZ9477_REG_PORT_OUT_RATE_0	0x0420 +#define KSZ9477_OUT_RATE_NO_LIMIT	0 + +#define KSZ9477_PORT_MRI_TC_MAP__4	0x0808 + +#define KSZ9477_PORT_TC_MAP_S		4 +#define KSZ9477_MAX_TC_PRIO		7 +  /* 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_MODE_M		GENMASK(7, 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_M			GENMASK(5, 4)  #define MTI_SHAPING_OFF			0  #define MTI_SHAPING_SRP			1  #define MTI_SHAPING_TIME_AWARE		2 +#define KSZ9477_PORT_MTI_QUEUE_CTRL_1	0x0915 +#define KSZ9477_DEFAULT_WRR_WEIGHT	1 +  #define REG_PORT_MTI_HI_WATER_MARK	0x0916  #define REG_PORT_MTI_LO_WATER_MARK	0x0918  |