diff options
Diffstat (limited to 'drivers/net/dsa')
| -rw-r--r-- | drivers/net/dsa/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz9477.c | 4 | ||||
| -rw-r--r-- | drivers/net/dsa/microchip/ksz9477_i2c.c | 2 | ||||
| -rw-r--r-- | drivers/net/dsa/mt7530.c | 26 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/net/dsa/qca/qca8k-8xxx.c | 164 | ||||
| -rw-r--r-- | drivers/net/dsa/qca/qca8k.h | 5 | 
7 files changed, 135 insertions, 77 deletions
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index c26755f662c1..f6f3b43dfb06 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -35,12 +35,13 @@ config NET_DSA_LANTIQ_GSWIP  	  the xrx200 / VR9 SoC.  config NET_DSA_MT7530 -	tristate "MediaTek MT753x and MT7621 Ethernet switch support" +	tristate "MediaTek MT7530 and MT7531 Ethernet switch support"  	select NET_DSA_TAG_MTK  	select MEDIATEK_GE_PHY  	help -	  This enables support for the MediaTek MT7530, MT7531, and MT7621 -	  Ethernet switch chips. +	  This enables support for the MediaTek MT7530 and MT7531 Ethernet +	  switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, +	  MT7621ST and MT7623AI SoCs is supported.  config NET_DSA_MV88E6060  	tristate "Marvell 88E6060 ethernet switch chip support" diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 47b54ecf2c6f..6178a96e389f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -540,10 +540,10 @@ int ksz9477_fdb_del(struct ksz_device *dev, int port,  		ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]);  		/* clear forwarding port */ -		alu_table[2] &= ~BIT(port); +		alu_table[1] &= ~BIT(port);  		/* if there is no port to forward, clear table */ -		if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { +		if ((alu_table[1] & ALU_V_PORT_MAP) == 0) {  			alu_table[0] = 0;  			alu_table[1] = 0;  			alu_table[2] = 0; diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index c1a633ca1e6d..e315f669ec06 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -104,7 +104,7 @@ static const struct of_device_id ksz9477_dt_ids[] = {  	},  	{  		.compatible = "microchip,ksz8563", -		.data = &ksz_switch_chips[KSZ9893] +		.data = &ksz_switch_chips[KSZ8563]  	},  	{  		.compatible = "microchip,ksz9567", diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 908fa89444c9..338f238f2043 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1309,14 +1309,26 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)  		if (!priv->ports[port].pvid)  			mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,  				   MT7530_VLAN_ACC_TAGGED); -	} -	/* Set the port as a user port which is to be able to recognize VID -	 * from incoming packets before fetching entry within the VLAN table. -	 */ -	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK, -		   VLAN_ATTR(MT7530_VLAN_USER) | -		   PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); +		/* Set the port as a user port which is to be able to recognize +		 * VID from incoming packets before fetching entry within the +		 * VLAN table. +		 */ +		mt7530_rmw(priv, MT7530_PVC_P(port), +			   VLAN_ATTR_MASK | PVC_EG_TAG_MASK, +			   VLAN_ATTR(MT7530_VLAN_USER) | +			   PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); +	} else { +		/* Also set CPU ports to the "user" VLAN port attribute, to +		 * allow VLAN classification, but keep the EG_TAG attribute as +		 * "consistent" (i.o.w. don't change its value) for packets +		 * received by the switch from the CPU, so that tagged packets +		 * are forwarded to user ports as tagged, and untagged as +		 * untagged. +		 */ +		mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, +			   VLAN_ATTR(MT7530_VLAN_USER)); +	}  }  static void diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig index 7a2445a34eb7..e3181d5471df 100644 --- a/drivers/net/dsa/mv88e6xxx/Kconfig +++ b/drivers/net/dsa/mv88e6xxx/Kconfig @@ -2,7 +2,6 @@  config NET_DSA_MV88E6XXX  	tristate "Marvell 88E6xxx Ethernet switch fabric support"  	depends on NET_DSA -	depends on PTP_1588_CLOCK_OPTIONAL  	select IRQ_DOMAIN  	select NET_DSA_TAG_EDSA  	select NET_DSA_TAG_DSA @@ -13,7 +12,8 @@ config NET_DSA_MV88E6XXX  config NET_DSA_MV88E6XXX_PTP  	bool "PTP support for Marvell 88E6xxx"  	default n -	depends on NET_DSA_MV88E6XXX && PTP_1588_CLOCK +	depends on (NET_DSA_MV88E6XXX = y && PTP_1588_CLOCK = y) || \ +	           (NET_DSA_MV88E6XXX = m && PTP_1588_CLOCK)  	help  	  Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch  	  chips that support it. diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index c5c3b4e92f28..2f224b166bbb 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -37,77 +37,104 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)  }  static int -qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) +qca8k_mii_write_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)  { -	u16 *cached_lo = &priv->mdio_cache.lo; -	struct mii_bus *bus = priv->bus;  	int ret; +	u16 lo; -	if (lo == *cached_lo) -		return 0; - +	lo = val & 0xffff;  	ret = bus->write(bus, phy_id, regnum, lo);  	if (ret < 0)  		dev_err_ratelimited(&bus->dev,  				    "failed to write qca8k 32bit lo register\n"); -	*cached_lo = lo; -	return 0; +	return ret;  }  static int -qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) +qca8k_mii_write_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)  { -	u16 *cached_hi = &priv->mdio_cache.hi; -	struct mii_bus *bus = priv->bus;  	int ret; +	u16 hi; -	if (hi == *cached_hi) -		return 0; - +	hi = (u16)(val >> 16);  	ret = bus->write(bus, phy_id, regnum, hi);  	if (ret < 0)  		dev_err_ratelimited(&bus->dev,  				    "failed to write qca8k 32bit hi register\n"); -	*cached_hi = hi; -	return 0; +	return ret;  }  static int -qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +qca8k_mii_read_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)  {  	int ret;  	ret = bus->read(bus, phy_id, regnum); -	if (ret >= 0) { -		*val = ret; -		ret = bus->read(bus, phy_id, regnum + 1); -		*val |= ret << 16; -	} +	if (ret < 0) +		goto err; -	if (ret < 0) { -		dev_err_ratelimited(&bus->dev, -				    "failed to read qca8k 32bit register\n"); -		*val = 0; -		return ret; -	} +	*val = ret & 0xffff; +	return 0; + +err: +	dev_err_ratelimited(&bus->dev, +			    "failed to read qca8k 32bit lo register\n"); +	*val = 0; + +	return ret; +} +static int +qca8k_mii_read_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +{ +	int ret; + +	ret = bus->read(bus, phy_id, regnum); +	if (ret < 0) +		goto err; + +	*val = ret << 16;  	return 0; + +err: +	dev_err_ratelimited(&bus->dev, +			    "failed to read qca8k 32bit hi register\n"); +	*val = 0; + +	return ret;  } -static void -qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) +static int +qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)  { -	u16 lo, hi; +	u32 hi, lo;  	int ret; -	lo = val & 0xffff; -	hi = (u16)(val >> 16); +	*val = 0; -	ret = qca8k_set_lo(priv, phy_id, regnum, lo); -	if (ret >= 0) -		ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); +	ret = qca8k_mii_read_lo(bus, phy_id, regnum, &lo); +	if (ret < 0) +		goto err; + +	ret = qca8k_mii_read_hi(bus, phy_id, regnum + 1, &hi); +	if (ret < 0) +		goto err; + +	*val = lo | hi; + +err: +	return ret; +} + +static void +qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) +{ +	if (qca8k_mii_write_lo(bus, phy_id, regnum, val) < 0) +		return; + +	qca8k_mii_write_hi(bus, phy_id, regnum + 1, val);  }  static int @@ -146,7 +173,16 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)  	command = get_unaligned_le32(&mgmt_ethhdr->command);  	cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); +  	len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); +	/* Special case for len of 15 as this is the max value for len and needs to +	 * be increased before converting it from word to dword. +	 */ +	if (len == 15) +		len++; + +	/* We can ignore odd value, we always round up them in the alloc function. */ +	len *= sizeof(u16);  	/* Make sure the seq match the requested packet */  	if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) @@ -193,17 +229,33 @@ static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *  	if (!skb)  		return NULL; -	/* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -	 * Actually for some reason the steps are: -	 * 0: nothing -	 * 1-4: first 4 byte -	 * 5-6: first 12 byte -	 * 7-15: all 16 byte +	/* Hdr mgmt length value is in step of word size. +	 * As an example to process 4 byte of data the correct length to set is 2. +	 * To process 8 byte 4, 12 byte 6, 16 byte 8... +	 * +	 * Odd values will always return the next size on the ack packet. +	 * (length of 3 (6 byte) will always return 8 bytes of data) +	 * +	 * This means that a value of 15 (0xf) actually means reading/writing 32 bytes +	 * of data. +	 * +	 * To correctly calculate the length we devide the requested len by word and +	 * round up. +	 * On the ack function we can skip the odd check as we already handle the +	 * case here.  	 */ -	if (len == 16) -		real_len = 15; -	else -		real_len = len; +	real_len = DIV_ROUND_UP(len, sizeof(u16)); + +	/* We check if the result len is odd and we round up another time to +	 * the next size. (length of 3 will be increased to 4 as switch will always +	 * return 8 bytes) +	 */ +	if (real_len % sizeof(u16) != 0) +		real_len++; + +	/* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ +	if (real_len == 16) +		real_len--;  	skb_reset_mac_header(skb);  	skb_set_network_header(skb, skb->len); @@ -417,7 +469,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)  	if (ret < 0)  		goto exit; -	qca8k_mii_write32(priv, 0x10 | r2, r1, val); +	qca8k_mii_write32(bus, 0x10 | r2, r1, val);  exit:  	mutex_unlock(&bus->mdio_lock); @@ -450,7 +502,7 @@ qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_  	val &= ~mask;  	val |= write_val; -	qca8k_mii_write32(priv, 0x10 | r2, r1, val); +	qca8k_mii_write32(bus, 0x10 | r2, r1, val);  exit:  	mutex_unlock(&bus->mdio_lock); @@ -688,9 +740,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)  	qca8k_split_addr(reg, &r1, &r2, &page); -	ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, +	ret = read_poll_timeout(qca8k_mii_read_hi, ret1, !(val & mask), 0,  				QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -				bus, 0x10 | r2, r1, &val); +				bus, 0x10 | r2, r1 + 1, &val);  	/* Check if qca8k_read has failed for a different reason  	 * before returnting -ETIMEDOUT @@ -725,14 +777,14 @@ qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data)  	if (ret)  		goto exit; -	qca8k_mii_write32(priv, 0x10 | r2, r1, val); +	qca8k_mii_write32(bus, 0x10 | r2, r1, val);  	ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,  				   QCA8K_MDIO_MASTER_BUSY);  exit:  	/* even if the busy_wait timeouts try to clear the MASTER_EN */ -	qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +	qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0);  	mutex_unlock(&bus->mdio_lock); @@ -762,18 +814,18 @@ qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum)  	if (ret)  		goto exit; -	qca8k_mii_write32(priv, 0x10 | r2, r1, val); +	qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, val);  	ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,  				   QCA8K_MDIO_MASTER_BUSY);  	if (ret)  		goto exit; -	ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); +	ret = qca8k_mii_read_lo(bus, 0x10 | r2, r1, &val);  exit:  	/* even if the busy_wait timeouts try to clear the MASTER_EN */ -	qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +	qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0);  	mutex_unlock(&bus->mdio_lock); @@ -1943,8 +1995,6 @@ qca8k_sw_probe(struct mdio_device *mdiodev)  	}  	priv->mdio_cache.page = 0xffff; -	priv->mdio_cache.lo = 0xffff; -	priv->mdio_cache.hi = 0xffff;  	/* Check the detected switch id */  	ret = qca8k_read_switch_id(priv); diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index 0b7a5cb12321..03514f7a20be 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -375,11 +375,6 @@ struct qca8k_mdio_cache {   * mdio writes   */  	u16 page; -/* lo and hi can also be cached and from Documentation we can skip one - * extra mdio write if lo or hi is didn't change. - */ -	u16 lo; -	u16 hi;  };  struct qca8k_pcs {  |