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

Merge branch 'dsa-microchip-ksz_switch-refactor'

Arun Ramadoss says:

====================
net: dsa: microchip: refactor the ksz switch init function

During the ksz_switch_register function, it calls the individual switches init
functions (ksz8795.c and ksz9477.c). Both these functions have few things in
common like, copying the chip specific data to struct ksz_dev, allocating
ksz_port memory and mib_names memory & cnt. And to add the new LAN937x series
switch, these allocations has to be replicated.
Based on the review feedback of LAN937x part support patch, refactored the
switch init function to move allocations to switch register.

Link:https://patchwork.kernel.org/project/netdevbpf/patch/20220504151755.11737-8-arun.ramadoss@microchip.com/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6431ce6c 008db08b
Loading
Loading
Loading
Loading
+18 −234
Original line number Diff line number Diff line
@@ -126,86 +126,6 @@ static u8 ksz8863_shifts[] = {
	[DYNAMIC_MAC_SRC_PORT]		= 20,
};

struct mib_names {
	char string[ETH_GSTRING_LEN];
};

static const struct mib_names ksz87xx_mib_names[] = {
	{ "rx_hi" },
	{ "rx_undersize" },
	{ "rx_fragments" },
	{ "rx_oversize" },
	{ "rx_jabbers" },
	{ "rx_symbol_err" },
	{ "rx_crc_err" },
	{ "rx_align_err" },
	{ "rx_mac_ctrl" },
	{ "rx_pause" },
	{ "rx_bcast" },
	{ "rx_mcast" },
	{ "rx_ucast" },
	{ "rx_64_or_less" },
	{ "rx_65_127" },
	{ "rx_128_255" },
	{ "rx_256_511" },
	{ "rx_512_1023" },
	{ "rx_1024_1522" },
	{ "rx_1523_2000" },
	{ "rx_2001" },
	{ "tx_hi" },
	{ "tx_late_col" },
	{ "tx_pause" },
	{ "tx_bcast" },
	{ "tx_mcast" },
	{ "tx_ucast" },
	{ "tx_deferred" },
	{ "tx_total_col" },
	{ "tx_exc_col" },
	{ "tx_single_col" },
	{ "tx_mult_col" },
	{ "rx_total" },
	{ "tx_total" },
	{ "rx_discards" },
	{ "tx_discards" },
};

static const struct mib_names ksz88xx_mib_names[] = {
	{ "rx" },
	{ "rx_hi" },
	{ "rx_undersize" },
	{ "rx_fragments" },
	{ "rx_oversize" },
	{ "rx_jabbers" },
	{ "rx_symbol_err" },
	{ "rx_crc_err" },
	{ "rx_align_err" },
	{ "rx_mac_ctrl" },
	{ "rx_pause" },
	{ "rx_bcast" },
	{ "rx_mcast" },
	{ "rx_ucast" },
	{ "rx_64_or_less" },
	{ "rx_65_127" },
	{ "rx_128_255" },
	{ "rx_256_511" },
	{ "rx_512_1023" },
	{ "rx_1024_1522" },
	{ "tx" },
	{ "tx_hi" },
	{ "tx_late_col" },
	{ "tx_pause" },
	{ "tx_bcast" },
	{ "tx_mcast" },
	{ "tx_ucast" },
	{ "tx_deferred" },
	{ "tx_total_col" },
	{ "tx_exc_col" },
	{ "tx_single_col" },
	{ "tx_mult_col" },
	{ "rx_discards" },
	{ "tx_discards" },
};

static bool ksz_is_ksz88x3(struct ksz_device *dev)
{
	return dev->chip_id == 0x8830;
@@ -306,7 +226,7 @@ static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
	masks = ksz8->masks;
	regs = ksz8->regs;

	ctrl_addr = addr + dev->reg_mib_cnt * port;
	ctrl_addr = addr + dev->info->reg_mib_cnt * port;
	ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);

	mutex_lock(&dev->alu_mutex);
@@ -343,7 +263,7 @@ static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
	masks = ksz8->masks;
	regs = ksz8->regs;

	addr -= dev->reg_mib_cnt;
	addr -= dev->info->reg_mib_cnt;
	ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
	ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0;
	ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
@@ -392,7 +312,7 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
	u32 data;
	u32 cur;

	addr -= dev->reg_mib_cnt;
	addr -= dev->info->reg_mib_cnt;
	ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
			   KSZ8863_MIB_PACKET_DROPPED_RX_0;
	ctrl_addr += port;
@@ -453,23 +373,21 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
	mib->cnt_ptr = 0;

	/* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
	while (mib->cnt_ptr < dev->reg_mib_cnt) {
	while (mib->cnt_ptr < dev->info->reg_mib_cnt) {
		dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
					&mib->counters[mib->cnt_ptr]);
		++mib->cnt_ptr;
	}

	/* last one in storage */
	dropped = &mib->counters[dev->mib_cnt];
	dropped = &mib->counters[dev->info->mib_cnt];

	/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
	while (mib->cnt_ptr < dev->mib_cnt) {
	while (mib->cnt_ptr < dev->info->mib_cnt) {
		dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
					dropped, &mib->counters[mib->cnt_ptr]);
		++mib->cnt_ptr;
	}
	mib->cnt_ptr = 0;
	memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
}

static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
@@ -1003,18 +921,6 @@ static u32 ksz8_sw_get_phy_flags(struct dsa_switch *ds, int port)
	return 0;
}

static void ksz8_get_strings(struct dsa_switch *ds, int port,
			     u32 stringset, uint8_t *buf)
{
	struct ksz_device *dev = ds->priv;
	int i;

	for (i = 0; i < dev->mib_cnt; i++) {
		memcpy(buf + i * ETH_GSTRING_LEN,
		       dev->mib_names[i].string, ETH_GSTRING_LEN);
	}
}

static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
{
	u8 data;
@@ -1036,13 +942,13 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
	int first, index, cnt;
	struct ksz_port *p;

	if ((uint)port < dev->port_cnt) {
	if ((uint)port < dev->info->port_cnt) {
		first = port;
		cnt = port + 1;
	} else {
		/* Flush all ports. */
		first = 0;
		cnt = dev->port_cnt;
		cnt = dev->info->port_cnt;
	}
	for (index = first; index < cnt; index++) {
		p = &dev->ports[index];
@@ -1118,7 +1024,7 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
		 * Remove Tag flag to be changed, unless there are no
		 * other VLANs currently configured.
		 */
		for (vid = 1; vid < dev->num_vlans; ++vid) {
		for (vid = 1; vid < dev->info->num_vlans; ++vid) {
			/* Skip the VID we are going to add or reconfigure */
			if (vid == vlan->vid)
				continue;
@@ -1389,7 +1295,7 @@ static int ksz8_handle_global_errata(struct dsa_switch *ds)
	 *   KSZ879x/KSZ877x/KSZ876x and some EEE link partners may result in
	 *   the link dropping.
	 */
	if (dev->ksz87xx_eee_link_erratum)
	if (dev->info->ksz87xx_eee_link_erratum)
		ret = ksz8_ind_write8(dev, TABLE_EEE, REG_IND_EEE_GLOB2_HI, 0);

	return ret;
@@ -1402,7 +1308,7 @@ static int ksz8_setup(struct dsa_switch *ds)
	int i, ret = 0;

	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
				       dev->num_vlans, GFP_KERNEL);
				       dev->info->num_vlans, GFP_KERNEL);
	if (!dev->vlan_cache)
		return -ENOMEM;

@@ -1446,7 +1352,7 @@ static int ksz8_setup(struct dsa_switch *ds)
			   (BROADCAST_STORM_VALUE *
			   BROADCAST_STORM_PROT_RATE) / 100);

	for (i = 0; i < (dev->num_vlans / 4); i++)
	for (i = 0; i < (dev->info->num_vlans / 4); i++)
		ksz8_r_vlan_entries(dev, i);

	/* Setup STP address for STP operation. */
@@ -1454,7 +1360,7 @@ static int ksz8_setup(struct dsa_switch *ds)
	ether_addr_copy(alu.mac, eth_stp_addr);
	alu.is_static = true;
	alu.is_override = true;
	alu.port_forward = dev->host_mask;
	alu.port_forward = dev->info->cpu_ports;

	ksz8_w_sta_mac_table(dev, 0, &alu);

@@ -1470,15 +1376,7 @@ static void ksz8_get_caps(struct dsa_switch *ds, int port,
{
	struct ksz_device *dev = ds->priv;

	if (port == dev->cpu_port) {
		__set_bit(PHY_INTERFACE_MODE_RMII,
			  config->supported_interfaces);
		__set_bit(PHY_INTERFACE_MODE_MII,
			  config->supported_interfaces);
	} else {
		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
			  config->supported_interfaces);
	}
	ksz_phylink_get_caps(ds, port, config);

	config->mac_capabilities = MAC_10 | MAC_100;

@@ -1504,7 +1402,7 @@ static const struct dsa_switch_ops ksz8_switch_ops = {
	.phylink_get_caps	= ksz8_get_caps,
	.phylink_mac_link_down	= ksz_mac_link_down,
	.port_enable		= ksz_enable_port,
	.get_strings		= ksz8_get_strings,
	.get_strings		= ksz_get_strings,
	.get_ethtool_stats	= ksz_get_ethtool_stats,
	.get_sset_count		= ksz_sset_count,
	.port_bridge_join	= ksz_port_bridge_join,
@@ -1571,140 +1469,26 @@ static int ksz8_switch_detect(struct ksz_device *dev)
	return 0;
}

struct ksz_chip_data {
	u16 chip_id;
	const char *dev_name;
	int num_vlans;
	int num_alus;
	int num_statics;
	int cpu_ports;
	int port_cnt;
	bool ksz87xx_eee_link_erratum;
};

static const struct ksz_chip_data ksz8_switch_chips[] = {
	{
		.chip_id = 0x8795,
		.dev_name = "KSZ8795",
		.num_vlans = 4096,
		.num_alus = 0,
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.ksz87xx_eee_link_erratum = true,
	},
	{
		/*
		 * WARNING
		 * =======
		 * KSZ8794 is similar to KSZ8795, except the port map
		 * contains a gap between external and CPU ports, the
		 * port map is NOT continuous. The per-port register
		 * map is shifted accordingly too, i.e. registers at
		 * offset 0x40 are NOT used on KSZ8794 and they ARE
		 * used on KSZ8795 for external port 3.
		 *           external  cpu
		 * KSZ8794   0,1,2      4
		 * KSZ8795   0,1,2,3    4
		 * KSZ8765   0,1,2,3    4
		 */
		.chip_id = 0x8794,
		.dev_name = "KSZ8794",
		.num_vlans = 4096,
		.num_alus = 0,
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 4,		/* total cpu and user ports */
		.ksz87xx_eee_link_erratum = true,
	},
	{
		.chip_id = 0x8765,
		.dev_name = "KSZ8765",
		.num_vlans = 4096,
		.num_alus = 0,
		.num_statics = 8,
		.cpu_ports = 0x10,	/* can be configured as cpu port */
		.port_cnt = 5,		/* total cpu and user ports */
		.ksz87xx_eee_link_erratum = true,
	},
	{
		.chip_id = 0x8830,
		.dev_name = "KSZ8863/KSZ8873",
		.num_vlans = 16,
		.num_alus = 0,
		.num_statics = 8,
		.cpu_ports = 0x4,	/* can be configured as cpu port */
		.port_cnt = 3,
	},
};

static int ksz8_switch_init(struct ksz_device *dev)
{
	struct ksz8 *ksz8 = dev->priv;
	int i;

	dev->ds->ops = &ksz8_switch_ops;

	for (i = 0; i < ARRAY_SIZE(ksz8_switch_chips); i++) {
		const struct ksz_chip_data *chip = &ksz8_switch_chips[i];

		if (dev->chip_id == chip->chip_id) {
			dev->name = chip->dev_name;
			dev->num_vlans = chip->num_vlans;
			dev->num_alus = chip->num_alus;
			dev->num_statics = chip->num_statics;
			dev->port_cnt = fls(chip->cpu_ports);
			dev->cpu_port = fls(chip->cpu_ports) - 1;
			dev->phy_port_cnt = dev->port_cnt - 1;
			dev->cpu_ports = chip->cpu_ports;
			dev->host_mask = chip->cpu_ports;
			dev->port_mask = (BIT(dev->phy_port_cnt) - 1) |
					 chip->cpu_ports;
			dev->ksz87xx_eee_link_erratum =
				chip->ksz87xx_eee_link_erratum;
			break;
		}
	}

	/* no switch found */
	if (!dev->cpu_ports)
		return -ENODEV;
	dev->cpu_port = fls(dev->info->cpu_ports) - 1;
	dev->phy_port_cnt = dev->info->port_cnt - 1;
	dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports;

	if (ksz_is_ksz88x3(dev)) {
		ksz8->regs = ksz8863_regs;
		ksz8->masks = ksz8863_masks;
		ksz8->shifts = ksz8863_shifts;
		dev->mib_cnt = ARRAY_SIZE(ksz88xx_mib_names);
		dev->mib_names = ksz88xx_mib_names;
	} else {
		ksz8->regs = ksz8795_regs;
		ksz8->masks = ksz8795_masks;
		ksz8->shifts = ksz8795_shifts;
		dev->mib_cnt = ARRAY_SIZE(ksz87xx_mib_names);
		dev->mib_names = ksz87xx_mib_names;
	}

	dev->reg_mib_cnt = MIB_COUNTER_NUM;

	dev->ports = devm_kzalloc(dev->dev,
				  dev->port_cnt * sizeof(struct ksz_port),
				  GFP_KERNEL);
	if (!dev->ports)
		return -ENOMEM;
	for (i = 0; i < dev->port_cnt; i++) {
		mutex_init(&dev->ports[i].mib.cnt_mutex);
		dev->ports[i].mib.counters =
			devm_kzalloc(dev->dev,
				     sizeof(u64) *
				     (dev->mib_cnt + 1),
				     GFP_KERNEL);
		if (!dev->ports[i].mib.counters)
			return -ENOMEM;
	}

	/* set the real number of ports */
	dev->ds->num_ports = dev->port_cnt;

	/* We rely on software untagging on the CPU port, so that we
	 * can support both tagged and untagged VLANs
	 */
+28 −7
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
static int ksz8795_spi_probe(struct spi_device *spi)
{
	const struct regmap_config *regmap_config;
	const struct ksz_chip_data *chip;
	struct device *ddev = &spi->dev;
	struct regmap_config rc;
	struct ksz_device *dev;
@@ -50,10 +51,15 @@ static int ksz8795_spi_probe(struct spi_device *spi)
	if (!dev)
		return -ENOMEM;

	regmap_config = device_get_match_data(ddev);
	if (!regmap_config)
	chip = device_get_match_data(ddev);
	if (!chip)
		return -EINVAL;

	if (chip->chip_id == KSZ8830_CHIP_ID)
		regmap_config = ksz8863_regmap_config;
	else
		regmap_config = ksz8795_regmap_config;

	for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
		rc = regmap_config[i];
		rc.lock_arg = &dev->regmap_mutex;
@@ -113,11 +119,26 @@ static void ksz8795_spi_shutdown(struct spi_device *spi)
}

static const struct of_device_id ksz8795_dt_ids[] = {
	{ .compatible = "microchip,ksz8765", .data = &ksz8795_regmap_config },
	{ .compatible = "microchip,ksz8794", .data = &ksz8795_regmap_config },
	{ .compatible = "microchip,ksz8795", .data = &ksz8795_regmap_config },
	{ .compatible = "microchip,ksz8863", .data = &ksz8863_regmap_config },
	{ .compatible = "microchip,ksz8873", .data = &ksz8863_regmap_config },
	{
		.compatible = "microchip,ksz8765",
		.data = &ksz_switch_chips[KSZ8765]
	},
	{
		.compatible = "microchip,ksz8794",
		.data = &ksz_switch_chips[KSZ8794]
	},
	{
		.compatible = "microchip,ksz8795",
		.data = &ksz_switch_chips[KSZ8795]
	},
	{
		.compatible = "microchip,ksz8863",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{
		.compatible = "microchip,ksz8873",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{},
};
MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
+8 −2
Original line number Diff line number Diff line
@@ -206,8 +206,14 @@ static void ksz8863_smi_shutdown(struct mdio_device *mdiodev)
}

static const struct of_device_id ksz8863_dt_ids[] = {
	{ .compatible = "microchip,ksz8863" },
	{ .compatible = "microchip,ksz8873" },
	{
		.compatible = "microchip,ksz8863",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{
		.compatible = "microchip,ksz8873",
		.data = &ksz_switch_chips[KSZ8830]
	},
	{ },
};
MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);
+27 −173
Original line number Diff line number Diff line
@@ -23,48 +23,6 @@
#define NEW_XMII			BIT(1)
#define IS_9893				BIT(2)

static const struct {
	int index;
	char string[ETH_GSTRING_LEN];
} ksz9477_mib_names[TOTAL_SWITCH_COUNTER_NUM] = {
	{ 0x00, "rx_hi" },
	{ 0x01, "rx_undersize" },
	{ 0x02, "rx_fragments" },
	{ 0x03, "rx_oversize" },
	{ 0x04, "rx_jabbers" },
	{ 0x05, "rx_symbol_err" },
	{ 0x06, "rx_crc_err" },
	{ 0x07, "rx_align_err" },
	{ 0x08, "rx_mac_ctrl" },
	{ 0x09, "rx_pause" },
	{ 0x0A, "rx_bcast" },
	{ 0x0B, "rx_mcast" },
	{ 0x0C, "rx_ucast" },
	{ 0x0D, "rx_64_or_less" },
	{ 0x0E, "rx_65_127" },
	{ 0x0F, "rx_128_255" },
	{ 0x10, "rx_256_511" },
	{ 0x11, "rx_512_1023" },
	{ 0x12, "rx_1024_1522" },
	{ 0x13, "rx_1523_2000" },
	{ 0x14, "rx_2001" },
	{ 0x15, "tx_hi" },
	{ 0x16, "tx_late_col" },
	{ 0x17, "tx_pause" },
	{ 0x18, "tx_bcast" },
	{ 0x19, "tx_mcast" },
	{ 0x1A, "tx_ucast" },
	{ 0x1B, "tx_deferred" },
	{ 0x1C, "tx_total_col" },
	{ 0x1D, "tx_exc_col" },
	{ 0x1E, "tx_single_col" },
	{ 0x1F, "tx_mult_col" },
	{ 0x80, "rx_total" },
	{ 0x81, "tx_total" },
	{ 0x82, "rx_discards" },
	{ 0x83, "tx_discards" },
};

static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
	regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
@@ -100,7 +58,7 @@ static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu)
	/* Cache the per-port MTU setting */
	dev->ports[port].max_frame = frame_size;

	for (i = 0; i < dev->port_cnt; i++)
	for (i = 0; i < dev->info->port_cnt; i++)
		max_frame = max(max_frame, dev->ports[i].max_frame);

	return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2,
@@ -287,7 +245,7 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
			      u64 *dropped, u64 *cnt)
{
	addr = ksz9477_mib_names[addr].index;
	addr = dev->info->mib_names[addr].index;
	ksz9477_r_mib_cnt(dev, port, addr, cnt);
}

@@ -316,9 +274,6 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
	ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH);
	ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0);
	mutex_unlock(&mib->cnt_mutex);

	mib->cnt_ptr = 0;
	memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
}

static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,
@@ -400,20 +355,6 @@ static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg,
	return 0;
}

static void ksz9477_get_strings(struct dsa_switch *ds, int port,
				u32 stringset, uint8_t *buf)
{
	int i;

	if (stringset != ETH_SS_STATS)
		return;

	for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) {
		memcpy(buf + i * ETH_GSTRING_LEN, ksz9477_mib_names[i].string,
		       ETH_GSTRING_LEN);
	}
}

static void ksz9477_cfg_port_member(struct ksz_device *dev, int port,
				    u8 member)
{
@@ -434,7 +375,7 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
			   SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S,
			   SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S);

	if (port < dev->port_cnt) {
	if (port < dev->info->port_cnt) {
		/* flush individual port */
		ksz_pread8(dev, port, P_STP_CTRL, &data);
		if (!(data & PORT_LEARN_DISABLE))
@@ -756,7 +697,7 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,

	mutex_lock(&dev->alu_mutex);

	for (index = 0; index < dev->num_statics; index++) {
	for (index = 0; index < dev->info->num_statics; index++) {
		/* find empty slot first */
		data = (index << ALU_STAT_INDEX_S) |
			ALU_STAT_READ | ALU_STAT_START;
@@ -787,7 +728,7 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
	}

	/* no available entry */
	if (index == dev->num_statics) {
	if (index == dev->info->num_statics) {
		err = -ENOSPC;
		goto exit;
	}
@@ -832,7 +773,7 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,

	mutex_lock(&dev->alu_mutex);

	for (index = 0; index < dev->num_statics; index++) {
	for (index = 0; index < dev->info->num_statics; index++) {
		/* find empty slot first */
		data = (index << ALU_STAT_INDEX_S) |
			ALU_STAT_READ | ALU_STAT_START;
@@ -861,7 +802,7 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
	}

	/* no available entry */
	if (index == dev->num_statics)
	if (index == dev->info->num_statics)
		goto exit;

	/* clear port */
@@ -903,7 +844,7 @@ static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port,
	 * Check if any of the port is already set for sniffing
	 * If yes, instruct the user to remove the previous entry & exit
	 */
	for (p = 0; p < dev->port_cnt; p++) {
	for (p = 0; p < dev->info->port_cnt; p++) {
		/* Skip the current sniffing port */
		if (p == mirror->to_local_port)
			continue;
@@ -946,7 +887,7 @@ static void ksz9477_port_mirror_del(struct dsa_switch *ds, int port,


	/* Check if any of the port is still referring to sniffer port */
	for (p = 0; p < dev->port_cnt; p++) {
	for (p = 0; p < dev->info->port_cnt; p++) {
		ksz_pread8(dev, p, P_MIRROR_CTRL, &data);

		if ((data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) {
@@ -1156,6 +1097,15 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
	ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee);
}

static void ksz9477_get_caps(struct dsa_switch *ds, int port,
			     struct phylink_config *config)
{
	ksz_phylink_get_caps(ds, port, config);

	config->mac_capabilities = MAC_10 | MAC_100 | MAC_1000FD |
				   MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
}

static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
	struct ksz_port *p = &dev->ports[port];
@@ -1194,7 +1144,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
			     PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL,
			     false);

		if (dev->phy_errata_9477)
		if (dev->info->phy_errata_9477)
			ksz9477_phy_errata_setup(dev, port);
	} else {
		/* force flow control */
@@ -1259,8 +1209,9 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
	struct ksz_port *p;
	int i;

	for (i = 0; i < dev->port_cnt; i++) {
		if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) {
	for (i = 0; i < dev->info->port_cnt; i++) {
		if (dsa_is_cpu_port(ds, i) &&
		    (dev->info->cpu_ports & (1 << i))) {
			phy_interface_t interface;
			const char *prev_msg;
			const char *prev_mode;
@@ -1304,7 +1255,7 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
		}
	}

	for (i = 0; i < dev->port_cnt; i++) {
	for (i = 0; i < dev->info->port_cnt; i++) {
		if (i == dev->cpu_port)
			continue;
		p = &dev->ports[i];
@@ -1328,7 +1279,7 @@ static int ksz9477_setup(struct dsa_switch *ds)
	int ret = 0;

	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
				       dev->num_vlans, GFP_KERNEL);
				       dev->info->num_vlans, GFP_KERNEL);
	if (!dev->vlan_cache)
		return -ENOMEM;

@@ -1380,8 +1331,9 @@ static const struct dsa_switch_ops ksz9477_switch_ops = {
	.phy_read		= ksz9477_phy_read16,
	.phy_write		= ksz9477_phy_write16,
	.phylink_mac_link_down	= ksz_mac_link_down,
	.phylink_get_caps	= ksz9477_get_caps,
	.port_enable		= ksz_enable_port,
	.get_strings		= ksz9477_get_strings,
	.get_strings		= ksz_get_strings,
	.get_ethtool_stats	= ksz_get_ethtool_stats,
	.get_sset_count		= ksz_sset_count,
	.port_bridge_join	= ksz_port_bridge_join,
@@ -1470,109 +1422,11 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
	return 0;
}

struct ksz_chip_data {
	u32 chip_id;
	const char *dev_name;
	int num_vlans;
	int num_alus;
	int num_statics;
	int cpu_ports;
	int port_cnt;
	bool phy_errata_9477;
};

static const struct ksz_chip_data ksz9477_switch_chips[] = {
	{
		.chip_id = 0x00947700,
		.dev_name = "KSZ9477",
		.num_vlans = 4096,
		.num_alus = 4096,
		.num_statics = 16,
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.phy_errata_9477 = true,
	},
	{
		.chip_id = 0x00989700,
		.dev_name = "KSZ9897",
		.num_vlans = 4096,
		.num_alus = 4096,
		.num_statics = 16,
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.phy_errata_9477 = true,
	},
	{
		.chip_id = 0x00989300,
		.dev_name = "KSZ9893",
		.num_vlans = 4096,
		.num_alus = 4096,
		.num_statics = 16,
		.cpu_ports = 0x07,	/* can be configured as cpu port */
		.port_cnt = 3,		/* total port count */
	},
	{
		.chip_id = 0x00956700,
		.dev_name = "KSZ9567",
		.num_vlans = 4096,
		.num_alus = 4096,
		.num_statics = 16,
		.cpu_ports = 0x7F,	/* can be configured as cpu port */
		.port_cnt = 7,		/* total physical port count */
		.phy_errata_9477 = true,
	},
};

static int ksz9477_switch_init(struct ksz_device *dev)
{
	int i;

	dev->ds->ops = &ksz9477_switch_ops;

	for (i = 0; i < ARRAY_SIZE(ksz9477_switch_chips); i++) {
		const struct ksz_chip_data *chip = &ksz9477_switch_chips[i];

		if (dev->chip_id == chip->chip_id) {
			dev->name = chip->dev_name;
			dev->num_vlans = chip->num_vlans;
			dev->num_alus = chip->num_alus;
			dev->num_statics = chip->num_statics;
			dev->port_cnt = chip->port_cnt;
			dev->cpu_ports = chip->cpu_ports;
			dev->phy_errata_9477 = chip->phy_errata_9477;

			break;
		}
	}

	/* no switch found */
	if (!dev->port_cnt)
		return -ENODEV;

	dev->port_mask = (1 << dev->port_cnt) - 1;

	dev->reg_mib_cnt = SWITCH_COUNTER_NUM;
	dev->mib_cnt = TOTAL_SWITCH_COUNTER_NUM;

	dev->ports = devm_kzalloc(dev->dev,
				  dev->port_cnt * sizeof(struct ksz_port),
				  GFP_KERNEL);
	if (!dev->ports)
		return -ENOMEM;
	for (i = 0; i < dev->port_cnt; i++) {
		spin_lock_init(&dev->ports[i].mib.stats64_lock);
		mutex_init(&dev->ports[i].mib.cnt_mutex);
		dev->ports[i].mib.counters =
			devm_kzalloc(dev->dev,
				     sizeof(u64) *
				     (TOTAL_SWITCH_COUNTER_NUM + 1),
				     GFP_KERNEL);
		if (!dev->ports[i].mib.counters)
			return -ENOMEM;
	}

	/* set the real number of ports */
	dev->ds->num_ports = dev->port_cnt;
	dev->port_mask = (1 << dev->info->port_cnt) - 1;

	return 0;
}
+24 −6
Original line number Diff line number Diff line
@@ -87,12 +87,30 @@ static const struct i2c_device_id ksz9477_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, ksz9477_i2c_id);

static const struct of_device_id ksz9477_dt_ids[] = {
	{ .compatible = "microchip,ksz9477" },
	{ .compatible = "microchip,ksz9897" },
	{ .compatible = "microchip,ksz9893" },
	{ .compatible = "microchip,ksz9563" },
	{ .compatible = "microchip,ksz9567" },
	{ .compatible = "microchip,ksz8563" },
	{
		.compatible = "microchip,ksz9477",
		.data = &ksz_switch_chips[KSZ9477]
	},
	{
		.compatible = "microchip,ksz9897",
		.data = &ksz_switch_chips[KSZ9897]
	},
	{
		.compatible = "microchip,ksz9893",
		.data = &ksz_switch_chips[KSZ9893]
	},
	{
		.compatible = "microchip,ksz9563",
		.data = &ksz_switch_chips[KSZ9893]
	},
	{
		.compatible = "microchip,ksz8563",
		.data = &ksz_switch_chips[KSZ9893]
	},
	{
		.compatible = "microchip,ksz9567",
		.data = &ksz_switch_chips[KSZ9567]
	},
	{},
};
MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
Loading