[PATCH 1/3] dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches
Document Microchip KSZ87xx family switches. These include KSZ8765 - 5 port switch KSZ8794 - 4 port switch KSZ8795 - 5 port switch Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Rob Herring Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Cc: devicet...@vger.kernel.org --- Documentation/devicetree/bindings/net/dsa/ksz.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 4ac21cef370e..5e8429b6f9ca 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -5,6 +5,9 @@ Required properties: - compatible: For external switch chips, compatible string must be exactly one of the following: + - "microchip,ksz8765" + - "microchip,ksz8794" + - "microchip,ksz8795" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" -- 2.20.1
[PATCH 0/3] net: dsa: ksz: Add Microchip KSZ87xx support
This series adds support for Microchip KSZ87xx switches, which are slightly simpler compared to KSZ9xxx . Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Marek Vasut (1): dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches Tristram Ha (2): net: dsa: ksz: Add KSZ8795 tag code net: dsa: ksz: Add Microchip KSZ8795 DSA driver .../devicetree/bindings/net/dsa/ksz.txt |3 + drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile|2 + drivers/net/dsa/microchip/ksz8795.c | 1360 + drivers/net/dsa/microchip/ksz8795_reg.h | 1004 drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.h| 28 + drivers/net/dsa/microchip/ksz_priv.h |1 + include/net/dsa.h |2 + net/dsa/Kconfig |7 + net/dsa/tag_ksz.c | 62 + 11 files changed, 2591 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c -- 2.20.1
[PATCH 2/3] net: dsa: ksz: Add KSZ8795 tag code
From: Tristram Ha Add DSA tag code for Microchip KSZ8795 switch. The switch is simpler and the tag is only 1 byte, instead of 2 as is the case with KSZ9477. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 7 ++ net/dsa/tag_ksz.c | 62 +++ 3 files changed, 71 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 1e8650fa8acc..147b757ef8ea 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -41,6 +41,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_TRAILER_VALUE11 #define DSA_TAG_PROTO_8021Q_VALUE 12 #define DSA_TAG_PROTO_SJA1105_VALUE13 +#define DSA_TAG_PROTO_KSZ8795_VALUE14 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -57,6 +58,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, + DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 6e942dda1bcd..423fa4370608 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -77,6 +77,13 @@ config NET_DSA_TAG_KSZ_COMMON tristate default n +config NET_DSA_TAG_KSZ8795 + tristate "Tag driver for Microchip 8795 family of switches" + select NET_DSA_TAG_KSZ_COMMON + help + Say Y if you want to enable support for tagging frames for the + Microchip 8795 family of switches. + config NET_DSA_TAG_KSZ tristate "Tag driver for Microchip 9893 family of switches" select NET_DSA_TAG_KSZ_COMMON diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index adc6c1e03a4c..dd5ac64b4748 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -69,6 +69,67 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, return skb; } +/* + * For Ingress (Host -> KSZ8795), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag(1byte)|FCS(4bytes) + * --- + * tag : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) + * + * For Egress (KSZ8795 -> Host), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x06=port7) + */ + +#define KSZ8795_INGRESS_TAG_LEN1 + +#define KSZ8795_TAIL_TAG_OVERRIDE BIT(6) +#define KSZ8795_TAIL_TAG_LOOKUPBIT(7) + +static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct sk_buff *nskb; + u8 *tag; + u8 *addr; + + nskb = ksz_common_xmit(skb, dev, KSZ8795_INGRESS_TAG_LEN); + if (!nskb) + return NULL; + + /* Tag encoding */ + tag = skb_put(nskb, KSZ8795_INGRESS_TAG_LEN); + addr = skb_mac_header(nskb); + + *tag = 1 << dp->index; + if (is_link_local_ether_addr(addr)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return nskb; +} + +static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + + return ksz_common_rcv(skb, dev, tag[0] & 7, KSZ_EGRESS_TAG_LEN); +} + +static const struct dsa_device_ops ksz8795_netdev_ops = { + .name = "ksz8795", + .proto = DSA_TAG_PROTO_KSZ8795, + .xmit = ksz8795_xmit, + .rcv= ksz8795_rcv, + .overhead = KSZ8795_INGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(ksz8795_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); + /* * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. * --- @@ -183,6 +244,7 @@ DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); static struct dsa_tag_driver *dsa_tag_driver_array[] = { + &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), }; -- 2.20.1
[PATCH 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
From: Tristram Ha Add Microchip KSZ8795 DSA driver. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile |2 + drivers/net/dsa/microchip/ksz8795.c | 1360 +++ drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.h | 28 + drivers/net/dsa/microchip/ksz_priv.h|1 + 7 files changed, 2517 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index fe0a13b79c4b..d990c7128991 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -16,3 +16,21 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI select REGMAP_SPI help Select to enable support for registering switches configured through SPI. + +menuconfig NET_DSA_MICROCHIP_KSZ8795 + tristate "Microchip KSZ8795 series switch support" + depends on NET_DSA + select NET_DSA_TAG_KSZ8795 + select NET_DSA_MICROCHIP_KSZ_COMMON + help + This driver adds support for Microchip KSZ8795 switch chips. + +config NET_DSA_MICROCHIP_KSZ8795_SPI + tristate "KSZ8795 series SPI connected switch driver" + depends on NET_DSA_MICROCHIP_KSZ8795 && SPI + select REGMAP_SPI + help + This driver accesses KSZ8795 chip through SPI. + + It is required to use the KSZ8795 switch driver as the only access + is through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 68451b02f775..e3d799b95d7d 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_common.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)+= ksz9477.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)+= ksz9477_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)+= ksz8795.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)+= ksz8795_spi.o diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c new file mode 100644 index ..c26aedf41a5f --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -0,0 +1,1360 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8795 switch driver + * + * Copyright (C) 2017 Microchip Technology Inc. + * Tristram Ha + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksz_priv.h" +#include "ksz_common.h" +#include "ksz8795_reg.h" + +static const struct { + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { "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 void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, +bool set) +{ + regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); +} + +static int ksz8795_reset_switch(struct ksz_device *dev) +{ + /* reset switch */ + ksz_write8(dev, REG_POWER_MANAGEMENT_
Re: [PATCH 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
On 7/25/19 4:03 PM, Andrew Lunn wrote: > On Wed, Jul 24, 2019 at 03:40:48PM +0200, Marek Vasut wrote: >> From: Tristram Ha >> +static void ksz8795_phy_setup(struct ksz_device *dev, int port, >> + struct phy_device *phy) >> +{ >> +if (port < dev->phy_port_cnt) { >> +/* >> + * SUPPORTED_Asym_Pause and SUPPORTED_Pause can be removed to >> + * disable flow control when rate limiting is used. >> + */ >> +linkmode_copy(phy->advertising, phy->supported); >> +} >> +} > > Hi Marek > > Do you know why this is needed? Unfortunately, no. It seems it copies supported features of the PHY to advertised features of the PHY for ports which are downstream (i.e. not the CPU port).
[PATCH V2 0/3] net: dsa: ksz: Add Microchip KSZ87xx support
This series adds support for Microchip KSZ87xx switches, which are slightly simpler compared to KSZ9xxx . Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Marek Vasut (1): dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches Tristram Ha (2): net: dsa: ksz: Add KSZ8795 tag code net: dsa: ksz: Add Microchip KSZ8795 DSA driver .../devicetree/bindings/net/dsa/ksz.txt |3 + drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile|2 + drivers/net/dsa/microchip/ksz8795.c | 1324 + drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.h| 28 + drivers/net/dsa/microchip/ksz_priv.h |1 + include/net/dsa.h |2 + net/dsa/Kconfig |7 + net/dsa/tag_ksz.c | 62 + 11 files changed, 2555 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c -- 2.20.1
[PATCH V2 1/3] dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches
Document Microchip KSZ87xx family switches. These include KSZ8765 - 5 port switch KSZ8794 - 4 port switch KSZ8795 - 5 port switch Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Rob Herring Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Cc: devicet...@vger.kernel.org --- V2: No change --- Documentation/devicetree/bindings/net/dsa/ksz.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 4ac21cef370e..5e8429b6f9ca 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -5,6 +5,9 @@ Required properties: - compatible: For external switch chips, compatible string must be exactly one of the following: + - "microchip,ksz8765" + - "microchip,ksz8794" + - "microchip,ksz8795" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" -- 2.20.1
[PATCH V2 2/3] net: dsa: ksz: Add KSZ8795 tag code
From: Tristram Ha Add DSA tag code for Microchip KSZ8795 switch. The switch is simpler and the tag is only 1 byte, instead of 2 as is the case with KSZ9477. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: No change --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 7 ++ net/dsa/tag_ksz.c | 62 +++ 3 files changed, 71 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 1e8650fa8acc..147b757ef8ea 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -41,6 +41,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_TRAILER_VALUE11 #define DSA_TAG_PROTO_8021Q_VALUE 12 #define DSA_TAG_PROTO_SJA1105_VALUE13 +#define DSA_TAG_PROTO_KSZ8795_VALUE14 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -57,6 +58,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, + DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 6e942dda1bcd..423fa4370608 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -77,6 +77,13 @@ config NET_DSA_TAG_KSZ_COMMON tristate default n +config NET_DSA_TAG_KSZ8795 + tristate "Tag driver for Microchip 8795 family of switches" + select NET_DSA_TAG_KSZ_COMMON + help + Say Y if you want to enable support for tagging frames for the + Microchip 8795 family of switches. + config NET_DSA_TAG_KSZ tristate "Tag driver for Microchip 9893 family of switches" select NET_DSA_TAG_KSZ_COMMON diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index adc6c1e03a4c..7af71db91c54 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -69,6 +69,67 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, return skb; } +/* + * For Ingress (Host -> KSZ8795), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag(1byte)|FCS(4bytes) + * --- + * tag : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) + * + * For Egress (KSZ8795 -> Host), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x06=port7) + */ + +#define KSZ8795_INGRESS_TAG_LEN1 + +#define KSZ8795_TAIL_TAG_OVERRIDE BIT(6) +#define KSZ8795_TAIL_TAG_LOOKUPBIT(7) + +static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct sk_buff *nskb; + u8 *tag; + u8 *addr; + + nskb = ksz_common_xmit(skb, dev, KSZ8795_INGRESS_TAG_LEN); + if (!nskb) + return NULL; + + /* Tag encoding */ + tag = skb_put(nskb, KSZ8795_INGRESS_TAG_LEN); + addr = skb_mac_header(nskb); + + *tag = 1 << dp->index; + if (is_link_local_ether_addr(addr)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return nskb; +} + +static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + + return ksz_common_rcv(skb, dev, tag[0] & 7, KSZ_EGRESS_TAG_LEN); +} + +static const struct dsa_device_ops ksz8795_netdev_ops = { + .name = "ksz8795", + .proto = DSA_TAG_PROTO_KSZ8795, + .xmit = ksz8795_xmit, + .rcv= ksz8795_rcv, + .overhead = KSZ8795_INGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(ksz8795_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); + /* * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. * --- @@ -183,6 +244,7 @@ DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); static struct dsa_tag_driver *dsa_tag_driver_array[] = { + &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), }; -- 2.20.1
[PATCH V2 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
From: Tristram Ha Add Microchip KSZ8795 DSA driver. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: - Use reverse xmas tree for variable declaration - Use BIT() macro where applicable - Use regmap_update_bits() where applicable - Replace ad-hoc stp_multicast_addr[] with ether_addr_copy(..., eth_stp_addr) --- drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile |2 + drivers/net/dsa/microchip/ksz8795.c | 1324 +++ drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.h | 28 + drivers/net/dsa/microchip/ksz_priv.h|1 + 7 files changed, 2481 insertions(+) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index fe0a13b79c4b..d990c7128991 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -16,3 +16,21 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI select REGMAP_SPI help Select to enable support for registering switches configured through SPI. + +menuconfig NET_DSA_MICROCHIP_KSZ8795 + tristate "Microchip KSZ8795 series switch support" + depends on NET_DSA + select NET_DSA_TAG_KSZ8795 + select NET_DSA_MICROCHIP_KSZ_COMMON + help + This driver adds support for Microchip KSZ8795 switch chips. + +config NET_DSA_MICROCHIP_KSZ8795_SPI + tristate "KSZ8795 series SPI connected switch driver" + depends on NET_DSA_MICROCHIP_KSZ8795 && SPI + select REGMAP_SPI + help + This driver accesses KSZ8795 chip through SPI. + + It is required to use the KSZ8795 switch driver as the only access + is through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 68451b02f775..e3d799b95d7d 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_common.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)+= ksz9477.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)+= ksz9477_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)+= ksz8795.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)+= ksz8795_spi.o diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c new file mode 100644 index ..f2408d5943db --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -0,0 +1,1324 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8795 switch driver + * + * Copyright (C) 2017 Microchip Technology Inc. + * Tristram Ha + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksz_priv.h" +#include "ksz_common.h" +#include "ksz8795_reg.h" + +static const struct { + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { "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 void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, +bool set) +{ + regmap_update_bits(dev->regmap[0],
Re: [PATCH 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
On 7/25/19 4:59 PM, Andrew Lunn wrote: > On Thu, Jul 25, 2019 at 04:56:37PM +0200, Marek Vasut wrote: >> On 7/25/19 4:03 PM, Andrew Lunn wrote: >>> On Wed, Jul 24, 2019 at 03:40:48PM +0200, Marek Vasut wrote: >>>> From: Tristram Ha >>>> +static void ksz8795_phy_setup(struct ksz_device *dev, int port, >>>> +struct phy_device *phy) >>>> +{ >>>> + if (port < dev->phy_port_cnt) { >>>> + /* >>>> + * SUPPORTED_Asym_Pause and SUPPORTED_Pause can be removed to >>>> + * disable flow control when rate limiting is used. >>>> + */ >>>> + linkmode_copy(phy->advertising, phy->supported); >>>> + } >>>> +} >>> >>> Hi Marek >>> >>> Do you know why this is needed? >> >> Unfortunately, no. >> >> It seems it copies supported features of the PHY to advertised features >> of the PHY for ports which are downstream (i.e. not the CPU port). > > Hi Marek > > Could you test it without this copy? Do you get sensible values from > ethtool? Does the pause configuration look sensible? They do look OK even without the code.
[PATCH V3 0/3] net: dsa: ksz: Add Microchip KSZ87xx support
This series adds support for Microchip KSZ87xx switches, which are slightly simpler compared to KSZ9xxx . Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Marek Vasut (1): dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches Tristram Ha (2): net: dsa: ksz: Add KSZ8795 tag code net: dsa: ksz: Add Microchip KSZ8795 DSA driver .../devicetree/bindings/net/dsa/ksz.txt |3 + drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile|2 + drivers/net/dsa/microchip/ksz8795.c | 1311 + drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.c|3 +- drivers/net/dsa/microchip/ksz_common.h| 28 + drivers/net/dsa/microchip/ksz_priv.h |1 + include/net/dsa.h |2 + net/dsa/Kconfig |7 + net/dsa/tag_ksz.c | 62 + 12 files changed, 2544 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c -- 2.20.1
[PATCH V3 1/3] dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches
Document Microchip KSZ87xx family switches. These include KSZ8765 - 5 port switch KSZ8794 - 4 port switch KSZ8795 - 5 port switch Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Rob Herring Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Cc: devicet...@vger.kernel.org --- V2: No change V3: No change --- Documentation/devicetree/bindings/net/dsa/ksz.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 4ac21cef370e..5e8429b6f9ca 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -5,6 +5,9 @@ Required properties: - compatible: For external switch chips, compatible string must be exactly one of the following: + - "microchip,ksz8765" + - "microchip,ksz8794" + - "microchip,ksz8795" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" -- 2.20.1
[PATCH V3 2/3] net: dsa: ksz: Add KSZ8795 tag code
From: Tristram Ha Add DSA tag code for Microchip KSZ8795 switch. The switch is simpler and the tag is only 1 byte, instead of 2 as is the case with KSZ9477. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: No change V3: No change --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 7 ++ net/dsa/tag_ksz.c | 62 +++ 3 files changed, 71 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 1e8650fa8acc..147b757ef8ea 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -41,6 +41,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_TRAILER_VALUE11 #define DSA_TAG_PROTO_8021Q_VALUE 12 #define DSA_TAG_PROTO_SJA1105_VALUE13 +#define DSA_TAG_PROTO_KSZ8795_VALUE14 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -57,6 +58,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, + DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 6e942dda1bcd..423fa4370608 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -77,6 +77,13 @@ config NET_DSA_TAG_KSZ_COMMON tristate default n +config NET_DSA_TAG_KSZ8795 + tristate "Tag driver for Microchip 8795 family of switches" + select NET_DSA_TAG_KSZ_COMMON + help + Say Y if you want to enable support for tagging frames for the + Microchip 8795 family of switches. + config NET_DSA_TAG_KSZ tristate "Tag driver for Microchip 9893 family of switches" select NET_DSA_TAG_KSZ_COMMON diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index adc6c1e03a4c..7af71db91c54 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -69,6 +69,67 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, return skb; } +/* + * For Ingress (Host -> KSZ8795), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag(1byte)|FCS(4bytes) + * --- + * tag : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) + * + * For Egress (KSZ8795 -> Host), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x06=port7) + */ + +#define KSZ8795_INGRESS_TAG_LEN1 + +#define KSZ8795_TAIL_TAG_OVERRIDE BIT(6) +#define KSZ8795_TAIL_TAG_LOOKUPBIT(7) + +static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct sk_buff *nskb; + u8 *tag; + u8 *addr; + + nskb = ksz_common_xmit(skb, dev, KSZ8795_INGRESS_TAG_LEN); + if (!nskb) + return NULL; + + /* Tag encoding */ + tag = skb_put(nskb, KSZ8795_INGRESS_TAG_LEN); + addr = skb_mac_header(nskb); + + *tag = 1 << dp->index; + if (is_link_local_ether_addr(addr)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return nskb; +} + +static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + + return ksz_common_rcv(skb, dev, tag[0] & 7, KSZ_EGRESS_TAG_LEN); +} + +static const struct dsa_device_ops ksz8795_netdev_ops = { + .name = "ksz8795", + .proto = DSA_TAG_PROTO_KSZ8795, + .xmit = ksz8795_xmit, + .rcv= ksz8795_rcv, + .overhead = KSZ8795_INGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(ksz8795_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); + /* * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. * --- @@ -183,6 +244,7 @@ DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); static struct dsa_tag_driver *dsa_tag_driver_array[] = { + &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), }; -- 2.20.1
[PATCH V3 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
From: Tristram Ha Add Microchip KSZ8795 DSA driver. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: - Use reverse xmas tree for variable declaration - Use BIT() macro where applicable - Use regmap_update_bits() where applicable - Replace ad-hoc stp_multicast_addr[] with ether_addr_copy(..., eth_stp_addr) V3: - Drop ksz8795_phy_setup() --- drivers/net/dsa/microchip/Kconfig | 18 + drivers/net/dsa/microchip/Makefile |2 + drivers/net/dsa/microchip/ksz8795.c | 1311 +++ drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.c |3 +- drivers/net/dsa/microchip/ksz_common.h | 28 + drivers/net/dsa/microchip/ksz_priv.h|1 + 8 files changed, 2470 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index fe0a13b79c4b..d990c7128991 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -16,3 +16,21 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI select REGMAP_SPI help Select to enable support for registering switches configured through SPI. + +menuconfig NET_DSA_MICROCHIP_KSZ8795 + tristate "Microchip KSZ8795 series switch support" + depends on NET_DSA + select NET_DSA_TAG_KSZ8795 + select NET_DSA_MICROCHIP_KSZ_COMMON + help + This driver adds support for Microchip KSZ8795 switch chips. + +config NET_DSA_MICROCHIP_KSZ8795_SPI + tristate "KSZ8795 series SPI connected switch driver" + depends on NET_DSA_MICROCHIP_KSZ8795 && SPI + select REGMAP_SPI + help + This driver accesses KSZ8795 chip through SPI. + + It is required to use the KSZ8795 switch driver as the only access + is through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 68451b02f775..e3d799b95d7d 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_common.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)+= ksz9477.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)+= ksz9477_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)+= ksz8795.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)+= ksz8795_spi.o diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c new file mode 100644 index ..ae80b3c6dea2 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -0,0 +1,1311 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8795 switch driver + * + * Copyright (C) 2017 Microchip Technology Inc. + * Tristram Ha + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksz_priv.h" +#include "ksz_common.h" +#include "ksz8795_reg.h" + +static const struct { + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { "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 void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +static void ksz_port_cfg(struct ksz_device *dev, int por
[PATCH V4 2/3] net: dsa: ksz: Add KSZ8795 tag code
From: Tristram Ha Add DSA tag code for Microchip KSZ8795 switch. The switch is simpler and the tag is only 1 byte, instead of 2 as is the case with KSZ9477. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: No change V3: No change V4: Drop Kconfig entry --- include/net/dsa.h | 2 ++ net/dsa/tag_ksz.c | 62 +++ 2 files changed, 64 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 1e8650fa8acc..147b757ef8ea 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -41,6 +41,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_TRAILER_VALUE11 #define DSA_TAG_PROTO_8021Q_VALUE 12 #define DSA_TAG_PROTO_SJA1105_VALUE13 +#define DSA_TAG_PROTO_KSZ8795_VALUE14 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -57,6 +58,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, + DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, }; struct packet_type; diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index adc6c1e03a4c..7af71db91c54 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -69,6 +69,67 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, return skb; } +/* + * For Ingress (Host -> KSZ8795), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag(1byte)|FCS(4bytes) + * --- + * tag : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) + * + * For Egress (KSZ8795 -> Host), 1 byte is added before FCS. + * --- + * DA(6bytes)|SA(6bytes)||Data(nbytes)|tag0(1byte)|FCS(4bytes) + * --- + * tag0 : zero-based value represents port + * (eg, 0x00=port1, 0x02=port3, 0x06=port7) + */ + +#define KSZ8795_INGRESS_TAG_LEN1 + +#define KSZ8795_TAIL_TAG_OVERRIDE BIT(6) +#define KSZ8795_TAIL_TAG_LOOKUPBIT(7) + +static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct sk_buff *nskb; + u8 *tag; + u8 *addr; + + nskb = ksz_common_xmit(skb, dev, KSZ8795_INGRESS_TAG_LEN); + if (!nskb) + return NULL; + + /* Tag encoding */ + tag = skb_put(nskb, KSZ8795_INGRESS_TAG_LEN); + addr = skb_mac_header(nskb); + + *tag = 1 << dp->index; + if (is_link_local_ether_addr(addr)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return nskb; +} + +static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; + + return ksz_common_rcv(skb, dev, tag[0] & 7, KSZ_EGRESS_TAG_LEN); +} + +static const struct dsa_device_ops ksz8795_netdev_ops = { + .name = "ksz8795", + .proto = DSA_TAG_PROTO_KSZ8795, + .xmit = ksz8795_xmit, + .rcv= ksz8795_rcv, + .overhead = KSZ8795_INGRESS_TAG_LEN, +}; + +DSA_TAG_DRIVER(ksz8795_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); + /* * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. * --- @@ -183,6 +244,7 @@ DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); static struct dsa_tag_driver *dsa_tag_driver_array[] = { + &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), }; -- 2.20.1
[PATCH V4 0/3] net: dsa: ksz: Add Microchip KSZ87xx support
This series adds support for Microchip KSZ87xx switches, which are slightly simpler compared to KSZ9xxx . Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Marek Vasut (1): dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches Tristram Ha (2): net: dsa: ksz: Add KSZ8795 tag code net: dsa: ksz: Add Microchip KSZ8795 DSA driver .../devicetree/bindings/net/dsa/ksz.txt |3 + drivers/net/dsa/microchip/Kconfig | 17 + drivers/net/dsa/microchip/Makefile|2 + drivers/net/dsa/microchip/ksz8795.c | 1311 + drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.c|3 +- drivers/net/dsa/microchip/ksz_common.h| 28 + drivers/net/dsa/microchip/ksz_priv.h |1 + include/net/dsa.h |2 + net/dsa/tag_ksz.c | 62 + 11 files changed, 2536 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c -- 2.20.1
[PATCH V4 3/3] net: dsa: ksz: Add Microchip KSZ8795 DSA driver
From: Tristram Ha Add Microchip KSZ8795 DSA driver. Signed-off-by: Tristram Ha Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- V2: - Use reverse xmas tree for variable declaration - Use BIT() macro where applicable - Use regmap_update_bits() where applicable - Replace ad-hoc stp_multicast_addr[] with ether_addr_copy(..., eth_stp_addr) V3: - Drop ksz8795_phy_setup() V4: - Update Kconfig entries, to not select the KSZ8795_DSA_TAG, which was removed --- drivers/net/dsa/microchip/Kconfig | 17 + drivers/net/dsa/microchip/Makefile |2 + drivers/net/dsa/microchip/ksz8795.c | 1311 +++ drivers/net/dsa/microchip/ksz8795_reg.h | 1004 + drivers/net/dsa/microchip/ksz8795_spi.c | 104 ++ drivers/net/dsa/microchip/ksz_common.c |3 +- drivers/net/dsa/microchip/ksz_common.h | 28 + drivers/net/dsa/microchip/ksz_priv.h|1 + 8 files changed, 2469 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/microchip/ksz8795.c create mode 100644 drivers/net/dsa/microchip/ksz8795_reg.h create mode 100644 drivers/net/dsa/microchip/ksz8795_spi.c diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index fe0a13b79c4b..5e4f74286ea3 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -16,3 +16,20 @@ config NET_DSA_MICROCHIP_KSZ9477_SPI select REGMAP_SPI help Select to enable support for registering switches configured through SPI. + +menuconfig NET_DSA_MICROCHIP_KSZ8795 + tristate "Microchip KSZ8795 series switch support" + depends on NET_DSA + select NET_DSA_MICROCHIP_KSZ_COMMON + help + This driver adds support for Microchip KSZ8795 switch chips. + +config NET_DSA_MICROCHIP_KSZ8795_SPI + tristate "KSZ8795 series SPI connected switch driver" + depends on NET_DSA_MICROCHIP_KSZ8795 && SPI + select REGMAP_SPI + help + This driver accesses KSZ8795 chip through SPI. + + It is required to use the KSZ8795 switch driver as the only access + is through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile index 68451b02f775..e3d799b95d7d 100644 --- a/drivers/net/dsa/microchip/Makefile +++ b/drivers/net/dsa/microchip/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON) += ksz_common.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)+= ksz9477.o obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)+= ksz9477_spi.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)+= ksz8795.o +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)+= ksz8795_spi.o diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c new file mode 100644 index ..ae80b3c6dea2 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -0,0 +1,1311 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip KSZ8795 switch driver + * + * Copyright (C) 2017 Microchip Technology Inc. + * Tristram Ha + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksz_priv.h" +#include "ksz_common.h" +#include "ksz8795_reg.h" + +static const struct { + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { "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 void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); +} + +s
[PATCH V4 1/3] dt-bindings: net: dsa: ksz: document Microchip KSZ87xx family switches
Document Microchip KSZ87xx family switches. These include KSZ8765 - 5 port switch KSZ8794 - 4 port switch KSZ8795 - 5 port switch Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Rob Herring Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh Cc: devicet...@vger.kernel.org --- V2: No change V3: No change V4: No change --- Documentation/devicetree/bindings/net/dsa/ksz.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/ksz.txt b/Documentation/devicetree/bindings/net/dsa/ksz.txt index 4ac21cef370e..5e8429b6f9ca 100644 --- a/Documentation/devicetree/bindings/net/dsa/ksz.txt +++ b/Documentation/devicetree/bindings/net/dsa/ksz.txt @@ -5,6 +5,9 @@ Required properties: - compatible: For external switch chips, compatible string must be exactly one of the following: + - "microchip,ksz8765" + - "microchip,ksz8794" + - "microchip,ksz8795" - "microchip,ksz9477" - "microchip,ksz9897" - "microchip,ksz9896" -- 2.20.1
[PATCH 3/3] net: dsa: ksz: Drop NET_DSA_TAG_KSZ9477
This Kconfig option is unused, drop it. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- drivers/net/dsa/microchip/Kconfig | 1 - net/dsa/Kconfig | 7 --- 2 files changed, 8 deletions(-) diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 5e4f74286ea3..e1c23d1e91e6 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -5,7 +5,6 @@ config NET_DSA_MICROCHIP_KSZ_COMMON menuconfig NET_DSA_MICROCHIP_KSZ9477 tristate "Microchip KSZ9477 series switch support" depends on NET_DSA - select NET_DSA_TAG_KSZ9477 select NET_DSA_MICROCHIP_KSZ_COMMON help This driver adds support for Microchip KSZ9477 switch chips. diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 6e942dda1bcd..2f69d4b53d46 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -84,13 +84,6 @@ config NET_DSA_TAG_KSZ Say Y if you want to enable support for tagging frames for the Microchip 9893 family of switches. -config NET_DSA_TAG_KSZ9477 - tristate "Tag driver for Microchip 9477 family of switches" - select NET_DSA_TAG_KSZ_COMMON - help - Say Y if you want to enable support for tagging frames for the - Microchip 9477 family of switches. - config NET_DSA_TAG_QCA tristate "Tag driver for Qualcomm Atheros QCA8K switches" help -- 2.20.1
[PATCH 2/3] net: dsa: ksz: Merge ksz_priv.h into ksz_common.h
Merge the two headers into one, no functional change. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz8795.c | 1 - drivers/net/dsa/microchip/ksz8795_spi.c | 1 - drivers/net/dsa/microchip/ksz9477.c | 1 - drivers/net/dsa/microchip/ksz9477_spi.c | 1 - drivers/net/dsa/microchip/ksz_common.c | 1 - drivers/net/dsa/microchip/ksz_common.h | 144 ++ drivers/net/dsa/microchip/ksz_priv.h| 156 7 files changed, 144 insertions(+), 161 deletions(-) delete mode 100644 drivers/net/dsa/microchip/ksz_priv.h diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index ae80b3c6dea2..a23d3ffdf0c4 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -18,7 +18,6 @@ #include #include -#include "ksz_priv.h" #include "ksz_common.h" #include "ksz8795_reg.h" diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index 50aa0d24effb..d0f8153e86b7 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -14,7 +14,6 @@ #include #include -#include "ksz_priv.h" #include "ksz_common.h" #define SPI_ADDR_SHIFT 12 diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index a8c97f7a79b7..187be42de5f1 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -14,7 +14,6 @@ #include #include -#include "ksz_priv.h" #include "ksz9477_reg.h" #include "ksz_common.h" diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 5a9e27b337a8..a226b389e12d 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -13,7 +13,6 @@ #include #include -#include "ksz_priv.h" #include "ksz_common.h" #define SPI_ADDR_SHIFT 24 diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index a1e6e560fde8..b45c7b972cec 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -18,7 +18,6 @@ #include #include -#include "ksz_priv.h" #include "ksz_common.h" void ksz_update_port_member(struct ksz_device *dev, int port) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 9f9ff0fb3b53..c44a8d23d973 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -7,7 +7,151 @@ #ifndef __KSZ_COMMON_H #define __KSZ_COMMON_H +#include +#include +#include +#include #include +#include + +struct vlan_table { + u32 table[3]; +}; + +struct ksz_port_mib { + struct mutex cnt_mutex; /* structure access */ + u8 cnt_ptr; + u64 *counters; +}; + +struct ksz_port { + u16 member; + u16 vid_member; + int stp_state; + struct phy_device phydev; + + u32 on:1; /* port is not disabled by hardware */ + u32 phy:1; /* port has a PHY */ + u32 fiber:1;/* port is fiber */ + u32 sgmii:1;/* port is SGMII */ + u32 force:1; + u32 read:1; /* read MIB counters in background */ + u32 freeze:1; /* MIB counter freeze is enabled */ + + struct ksz_port_mib mib; +}; + +struct ksz_device { + struct dsa_switch *ds; + struct ksz_platform_data *pdata; + const char *name; + + struct mutex dev_mutex; /* device access */ + struct mutex stats_mutex; /* status access */ + struct mutex alu_mutex; /* ALU access */ + struct mutex vlan_mutex;/* vlan access */ + const struct ksz_dev_ops *dev_ops; + + struct device *dev; + struct regmap *regmap[3]; + + void *priv; + + struct gpio_desc *reset_gpio; /* Optional reset GPIO */ + + /* chip specific data */ + u32 chip_id; + int num_vlans; + int num_alus; + int num_statics; + int cpu_port; /* port connected to CPU */ + int cpu_ports; /* port bitmap can be cpu port */ + int phy_port_cnt; + int port_cnt; + int reg_mib_cnt; + int mib_cnt; + int mib_port_cnt; + int last_port; /* ports after that not used */ + phy_interface_t interface; + u32 regs_size; + bool phy_errata_9477; + bool synclko_125; + + struct vlan_table *vlan_cache; + + struct ksz_port *ports; + struct timer_list mib_read_timer; + struct work_str
[PATCH 1/3] net: dsa: ksz: Remove dead code and fix warnings
Remove ksz_port_cleanup(), which is unused. Add missing include "ksz_common.h", which fixes the following warning when built with make ... W=1 drivers/net/dsa/microchip/ksz_common.c:23:6: warning: no previous prototype for ‘...’ [-Wmissing-prototypes] Note that the order of the headers cannot be swapped, as that would trigger missing forward declaration errors, which would indicate the way forward is to merge the two headers into one. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Florian Fainelli Cc: Tristram Ha Cc: Vivien Didelot Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz_common.c | 11 +-- drivers/net/dsa/microchip/ksz_common.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index ce20cc90f9ef..a1e6e560fde8 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -19,16 +19,7 @@ #include #include "ksz_priv.h" - -void ksz_port_cleanup(struct ksz_device *dev, int port) -{ - /* Common code for port cleanup. */ - mutex_lock(&dev->dev_mutex); - dev->on_ports &= ~(1 << port); - dev->live_ports &= ~(1 << port); - mutex_unlock(&dev->dev_mutex); -} -EXPORT_SYMBOL_GPL(ksz_port_cleanup); +#include "ksz_common.h" void ksz_update_port_member(struct ksz_device *dev, int port) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 84fed4a2578b..9f9ff0fb3b53 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -9,7 +9,6 @@ #include -void ksz_port_cleanup(struct ksz_device *dev, int port); void ksz_update_port_member(struct ksz_device *dev, int port); void ksz_init_mib_timer(struct ksz_device *dev); -- 2.20.1
Re: [PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
On 1/11/21 3:47 PM, Andrew Lunn wrote: On Mon, Jan 11, 2021 at 01:53:37PM +0100, Marek Vasut wrote: Unless the internal PHY is connected and started, the phylib will not poll the PHY for state and produce state updates. Connect the PHY and start/stop it. Hi Marek Please continue the conversion and remove all mii_calls. ks8851_set_link_ksettings() calling mii_ethtool_set_link_ksettings() is not good, phylib will not know about changes which we made to the PHY etc. Hi, I noticed a couple of drivers implement both the mii and mdiobus options, I was pondering why is that. Is there some legacy backward compatibility reason for keeping both or is it safe to remove the mii support completely from the driver? Either way, I will do that in a separate patch, so it could be reverted if it breaks something.
Re: [PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
On 1/11/21 3:43 PM, Heiner Kallweit wrote: On 11.01.2021 15:10, Marek Vasut wrote: On 1/11/21 2:50 PM, Heiner Kallweit wrote: On 11.01.2021 14:38, Marek Vasut wrote: On 1/11/21 2:26 PM, Heiner Kallweit wrote: [...] LGTM. When having a brief look at the driver I stumbled across two things: 1. Do MAC/PHY support any pause mode? Then a call to phy_support_(a)sym_pause() would be missing. https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ8851-16MLL-Single-Port-Ethernet-MAC-Controller-with-8-Bit-or-16-Bit-Non-PCI-Interface-DS2357B.pdf page 64 https://www.mouser.com/datasheet/2/268/ksz8851-16mll_ds-776208.pdf page 65 The later is more complete. Apparently it does support pause. Based on the datasheet, does it support sym or asym pause ? According to the description of flow control on p.23 it can support asym pause. However on the MAC side flow control doesn't seem to be always active, it's controlled by these two bits: p.49, TXCR, bit 3 p.50, RXCR1, bit 10 Default seems to be that flow control is disabled. So I guess this patch is OK as-is ?
Re: [PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
On 1/14/21 2:54 PM, Andrew Lunn wrote: On Tue, Jan 12, 2021 at 11:28:00PM +0100, Marek Vasut wrote: On 1/11/21 3:47 PM, Andrew Lunn wrote: On Mon, Jan 11, 2021 at 01:53:37PM +0100, Marek Vasut wrote: Unless the internal PHY is connected and started, the phylib will not poll the PHY for state and produce state updates. Connect the PHY and start/stop it. Hi Marek Please continue the conversion and remove all mii_calls. ks8851_set_link_ksettings() calling mii_ethtool_set_link_ksettings() is not good, phylib will not know about changes which we made to the PHY etc. Hi, I noticed a couple of drivers implement both the mii and mdiobus options. Which ones? boardcom b44.c and bcm63xx_enet.c for example Simply getting the link status might be safe, but if set_link_ksettings() or get_link_ksettings() is used, phylib is going to get confused when the PHY is changed without it knowing.. So please do remove all the mii calls as part of the patchset. Isn't that gonna break some ABI ? Also, is separate patch OK ?
[PATCH net-next] net: ks8851: Fix mixed module/builtin build
When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by including the ks8851_common.c in both ks8851_spi.c and ks8851_par.c. The DEBUG macro is defined in ks8851_common.c, so it does not have to be defined again. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Jakub Kicinski Cc: Lukas Wunner --- NOTE: Maybe there is a better way? --- drivers/net/ethernet/micrel/Makefile | 4 ++-- drivers/net/ethernet/micrel/ks8851_par.c | 2 +- drivers/net/ethernet/micrel/ks8851_spi.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/micrel/Makefile b/drivers/net/ethernet/micrel/Makefile index 5cc00d22c708..1aedfe0ecaf1 100644 --- a/drivers/net/ethernet/micrel/Makefile +++ b/drivers/net/ethernet/micrel/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_KS8851) += ks8851.o -ks8851-objs = ks8851_common.o ks8851_spi.o +ks8851-objs = ks8851_spi.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o -ks8851_mll-objs = ks8851_common.o ks8851_par.o +ks8851_mll-objs = ks8851_par.o obj-$(CONFIG_KSZ884X_PCI) += ksz884x.o diff --git a/drivers/net/ethernet/micrel/ks8851_par.c b/drivers/net/ethernet/micrel/ks8851_par.c index 3bab0cb2b1a5..e9131cc8a57b 100644 --- a/drivers/net/ethernet/micrel/ks8851_par.c +++ b/drivers/net/ethernet/micrel/ks8851_par.c @@ -8,7 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define DEBUG +#include "ks8851_common.c" #include #include diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c index 4ec7f1615977..53779d66f747 100644 --- a/drivers/net/ethernet/micrel/ks8851_spi.c +++ b/drivers/net/ethernet/micrel/ks8851_spi.c @@ -8,7 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define DEBUG +#include "ks8851_common.c" #include #include -- 2.29.2
Re: [PATCH net-next] net: ks8851: Fix mixed module/builtin build
On 1/15/21 4:00 PM, Andrew Lunn wrote: On Fri, Jan 15, 2021 at 02:42:39PM +0100, Marek Vasut wrote: When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by including the ks8851_common.c in both ks8851_spi.c and ks8851_par.c. The DEBUG macro is defined in ks8851_common.c, so it does not have to be defined again. DEBUG should not be defined for production code. So i would remove it altogether. There is kconfig'ury you can use to make them both the same. But i'm not particularly good with it. We had discussion about this module/builtin topic in ks8851 before, so I was hoping someone might provide a better suggestion.
Re: [PATCH net-next] net: ks8851: Fix mixed module/builtin build
On 1/15/21 4:59 PM, Andrew Lunn wrote: On Fri, Jan 15, 2021 at 04:05:57PM +0100, Marek Vasut wrote: On 1/15/21 4:00 PM, Andrew Lunn wrote: On Fri, Jan 15, 2021 at 02:42:39PM +0100, Marek Vasut wrote: When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by including the ks8851_common.c in both ks8851_spi.c and ks8851_par.c. The DEBUG macro is defined in ks8851_common.c, so it does not have to be defined again. DEBUG should not be defined for production code. So i would remove it altogether. There is kconfig'ury you can use to make them both the same. But i'm not particularly good with it. We had discussion about this module/builtin topic in ks8851 before, so I was hoping someone might provide a better suggestion. Try Arnd Bergmann. He is good with this sort of thing. Adding to CC.
Re: [PATCH] net: ks8851: remove definition of DEBUG
On 1/15/21 4:31 PM, t...@redhat.com wrote: From: Tom Rix Defining DEBUG should only be done in development. So remove DEBUG. Signed-off-by: Tom Rix Reviewed-by: Marek Vasut Thanks
[PATCH net-next V2] net: ks8851: Fix mixed module/builtin build
When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by passing THIS_MODULE as argument to ks8851_probe_common(), ks8851_register_mdiobus(), and ultimately __mdiobus_register() in the ks8851_common.c. Fixes: ef3631220d2b ("net: ks8851: Register MDIO bus and the internal PHY") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Arnd Bergmann Cc: Heiner Kallweit Cc: Jakub Kicinski Cc: Lukas Wunner --- V2: Pass the THIS_MODULE into ks8851_common.c --- drivers/net/ethernet/micrel/ks8851.h| 2 +- drivers/net/ethernet/micrel/ks8851_common.c | 9 + drivers/net/ethernet/micrel/ks8851_par.c| 2 +- drivers/net/ethernet/micrel/ks8851_spi.c| 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index ef13929036cf..037138fc6cb4 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -428,7 +428,7 @@ struct ks8851_net { }; int ks8851_probe_common(struct net_device *netdev, struct device *dev, - int msg_en); + int msg_en, struct module *owner); int ks8851_remove_common(struct device *dev); int ks8851_suspend(struct device *dev); int ks8851_resume(struct device *dev); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index f1996787bba5..88303ba4869d 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -1104,7 +1104,8 @@ int ks8851_resume(struct device *dev) } #endif -static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) +static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev, + struct module *owner) { struct phy_device *phy_dev; struct mii_bus *mii_bus; @@ -1122,7 +1123,7 @@ static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) mii_bus->phy_mask = ~((u32)BIT(0)); snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); - ret = mdiobus_register(mii_bus); + ret = __mdiobus_register(mii_bus, owner); if (ret) goto err_mdiobus_register; @@ -1149,7 +1150,7 @@ static void ks8851_unregister_mdiobus(struct ks8851_net *ks) } int ks8851_probe_common(struct net_device *netdev, struct device *dev, - int msg_en) + int msg_en, struct module *owner) { struct ks8851_net *ks = netdev_priv(netdev); unsigned cider; @@ -1224,7 +1225,7 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, dev_info(dev, "message enable is %d\n", msg_en); - ret = ks8851_register_mdiobus(ks, dev); + ret = ks8851_register_mdiobus(ks, dev, owner); if (ret) goto err_mdio; diff --git a/drivers/net/ethernet/micrel/ks8851_par.c b/drivers/net/ethernet/micrel/ks8851_par.c index 3bab0cb2b1a5..d6fc53d3efbb 100644 --- a/drivers/net/ethernet/micrel/ks8851_par.c +++ b/drivers/net/ethernet/micrel/ks8851_par.c @@ -324,7 +324,7 @@ static int ks8851_probe_par(struct platform_device *pdev) netdev->irq = platform_get_irq(pdev, 0); - return ks8851_probe_common(netdev, dev, msg_enable); + return ks8851_probe_common(netdev, dev, msg_enable, THIS_MODULE); } static int ks8851_remove_par(struct platform_device *pdev) diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c index 4ec7f1615977..9fbb7a548580 100644 --- a/drivers/net/ethernet/micrel/ks8851_spi.c +++ b/drivers/net/ethernet/micrel/ks8851_spi.c @@ -451,7 +451,7 @@ static int ks8851_probe_spi(struct spi_device *spi) netdev->irq = spi->irq; - return ks8851_probe_common(netdev, dev, msg_enable); + return ks8851_probe_common(netdev, dev, msg_enable, THIS_MODULE); } static int ks8851_remove_spi(struct spi_device *spi) -- 2.29.2
Re: [PATCH net-next] net: ks8851: Fix mixed module/builtin build
On 1/15/21 10:36 PM, Arnd Bergmann wrote: On Fri, Jan 15, 2021 at 6:24 PM Heiner Kallweit wrote: On 15.01.2021 16:59, Andrew Lunn wrote: On Fri, Jan 15, 2021 at 04:05:57PM +0100, Marek Vasut wrote: On 1/15/21 4:00 PM, Andrew Lunn wrote: On Fri, Jan 15, 2021 at 02:42:39PM +0100, Marek Vasut wrote: When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by including the ks8851_common.c in both ks8851_spi.c and ks8851_par.c. The DEBUG macro is defined in ks8851_common.c, so it does not have to be defined again. DEBUG should not be defined for production code. So i would remove it altogether. There is kconfig'ury you can use to make them both the same. But i'm not particularly good with it. We had discussion about this module/builtin topic in ks8851 before, so I was hoping someone might provide a better suggestion. Try Arnd Bergmann. He is good with this sort of thing. I'd say make ks8851_common.c a separate module. Then, if one of SPI / PAR is built in, ks8851_common needs to be built in too. To do so you'd have export all symbols from ks8851_common that you want to use in SPI /PAR. Yes, that should work, as long the common module does not reference any symbols from the other two modules (it normally wouldn't), and all globals in the common one are exported. You can also link everything into a single module, but then you have to deal with registering two device_driver structures from a single init function, which would undo some of cleanup. Maybe just passing THIS_MODULE around is even better way to do it, I CCed you on the V2, [PATCH net-next V2] net: ks8851: Fix mixed module/builtin build .
Re: [PATCH net-next V2] net: ks8851: Fix mixed module/builtin build
On 1/16/21 6:04 PM, Arnd Bergmann wrote: On Sat, Jan 16, 2021 at 5:48 PM Marek Vasut wrote: When either the SPI or PAR variant is compiled as module AND the other variant is compiled as built-in, the following build error occurs: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0x1564): undefined reference to `__this_module' Fix this by passing THIS_MODULE as argument to ks8851_probe_common(), ks8851_register_mdiobus(), and ultimately __mdiobus_register() in the ks8851_common.c. Fixes: ef3631220d2b ("net: ks8851: Register MDIO bus and the internal PHY") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Arnd Bergmann Cc: Heiner Kallweit Cc: Jakub Kicinski Cc: Lukas Wunner I don't really like this version, as it does not actually solve the problem of linking the same object file into both vmlinux and a loadable module, which can have all kinds of side-effects besides that link failure you saw. If you want to avoid exporting all those symbols, a simpler hack would be to '#include "ks8851_common.c" from each of the two files, which then always duplicates the contents (even when both are built-in), but at least builds the file the correct way. That's the same as V1, isn't it ?
Re: [PATCH net-next V2] net: ks8851: Fix mixed module/builtin build
On 1/16/21 9:39 PM, Lukas Wunner wrote: On Sat, Jan 16, 2021 at 08:26:22PM +0100, Arnd Bergmann wrote: On Sat, Jan 16, 2021 at 6:56 PM Marek Vasut wrote: On 1/16/21 6:04 PM, Arnd Bergmann wrote: On Sat, Jan 16, 2021 at 5:48 PM Marek Vasut wrote: I don't really like this version, as it does not actually solve the problem of linking the same object file into both vmlinux and a loadable module, which can have all kinds of side-effects besides that link failure you saw. If you want to avoid exporting all those symbols, a simpler hack would be to '#include "ks8851_common.c" from each of the two files, which then always duplicates the contents (even when both are built-in), but at least builds the file the correct way. That's the same as V1, isn't it ? Ah, I had not actually looked at the original submission, but yes, that was slightly better than v2, provided you make all symbols static to avoid the new link error. I still think that having three modules and exporting the symbols from the common part as Heiner Kallweit suggested would be the best way to do it. FWIW I'd prefer V1 (the #include approach) as it allows going back to using static inlines for register access. That's what we had before 7a552c850c45. It seems unlikely that a system uses both, the parallel *and* the SPI variant of the ks8851. So the additional memory necessary because of code duplication wouldn't matter in practice. I have a board with both options populated on my desk, sorry.
[PATCH net-next] net: dsa: microchip: ksz8795: Fix KSZ8794 port map again
The KSZ8795 switch has 4 external ports {0,1,2,3} and 1 CPU port {4}, so does the KSZ8765. The KSZ8794 seems to be repackaged KSZ8795 with different ID and port 3 not routed out, however the port 3 registers are present in the silicon, so the KSZ8794 switch has 3 external ports {0,1,2} and 1 CPU port {4}. Currently the driver always uses the last port as CPU port, on KSZ8795/KSZ8765 that is port 4 and that is OK, but on KSZ8794 that is port 3 and that is not OK, as it must also be port 4. This patch adjusts the driver such that it always registers a switch with 5 ports total (4 external ports, 1 CPU port), always sets the CPU port to switch port 4, and then configures the external port mask according to the switch model -- 3 ports for KSZ8794 and 4 for KSZ8795/KSZ8765. Fixes: 68a1b676db52 ("net: dsa: microchip: ksz8795: remove superfluous port_cnt assignment") Fixes: 4ce2a984abd8 ("net: dsa: microchip: ksz8795: use phy_port_cnt where possible") Fixes: 241ed719bc98 ("net: dsa: microchip: ksz8795: use port_cnt instead of TOTOAL_PORT_NUM") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Michael Grzeschik Cc: Jakub Kicinski --- NOTE: In case of KSZ8794, the DT node port@4 is the CPU port and port@3 should not be defined. --- drivers/net/dsa/microchip/ksz8795.c | 30 +++-- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index c973db101b72..a4570ba29c83 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1187,6 +1187,20 @@ static const struct ksz_chip_data ksz8795_switch_chips[] = { .port_cnt = 5, /* total cpu and user ports */ }, { + /* +* 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,34 +* KSZ8765 0,1,2,34 +*/ .chip_id = 0x8794, .dev_name = "KSZ8794", .num_vlans = 4096, @@ -1220,9 +1234,13 @@ static int ksz8795_switch_init(struct ksz_device *dev) 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->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; break; } } @@ -1231,17 +1249,9 @@ static int ksz8795_switch_init(struct ksz_device *dev) if (!dev->cpu_ports) return -ENODEV; - dev->port_mask = BIT(dev->port_cnt) - 1; - dev->port_mask |= dev->host_mask; - dev->reg_mib_cnt = KSZ8795_COUNTER_NUM; dev->mib_cnt = ARRAY_SIZE(mib_names); - dev->phy_port_cnt = dev->port_cnt - 1; - - dev->cpu_port = dev->port_cnt - 1; - dev->host_mask = BIT(dev->cpu_port); - dev->ports = devm_kzalloc(dev->dev, dev->port_cnt * sizeof(struct ksz_port), GFP_KERNEL); -- 2.29.2
[PATCH net-next V2] net: dsa: microchip: ksz8795: Fix KSZ8794 port map again
The KSZ8795 switch has 4 external ports {0,1,2,3} and 1 CPU port {4}, so does the KSZ8765. The KSZ8794 seems to be repackaged KSZ8795 with different ID and port 3 not routed out, however the port 3 registers are present in the silicon, so the KSZ8794 switch has 3 external ports {0,1,2} and 1 CPU port {4}. Currently the driver always uses the last port as CPU port, on KSZ8795/KSZ8765 that is port 4 and that is OK, but on KSZ8794 that is port 3 and that is not OK, as it must also be port 4. This patch adjusts the driver such that it always registers a switch with 5 ports total (4 external ports, 1 CPU port), always sets the CPU port to switch port 4, and then configures the external port mask according to the switch model -- 3 ports for KSZ8794 and 4 for KSZ8795/KSZ8765. Fixes: 68a1b676db52 ("net: dsa: microchip: ksz8795: remove superfluous port_cnt assignment") Fixes: 4ce2a984abd8 ("net: dsa: microchip: ksz8795: use phy_port_cnt where possible") Fixes: 241ed719bc98 ("net: dsa: microchip: ksz8795: use port_cnt instead of TOTOAL_PORT_NUM") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Michael Grzeschik Cc: Jakub Kicinski --- V2: - In case of KSZ8794, the DT node port@4 is the CPU port and port@3 should not be defined. Validate this condition in ksz_common.c --- drivers/net/dsa/microchip/ksz8795.c| 30 +- drivers/net/dsa/microchip/ksz_common.c | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index c973db101b72..a4570ba29c83 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1187,6 +1187,20 @@ static const struct ksz_chip_data ksz8795_switch_chips[] = { .port_cnt = 5, /* total cpu and user ports */ }, { + /* +* 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,34 +* KSZ8765 0,1,2,34 +*/ .chip_id = 0x8794, .dev_name = "KSZ8794", .num_vlans = 4096, @@ -1220,9 +1234,13 @@ static int ksz8795_switch_init(struct ksz_device *dev) 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->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; break; } } @@ -1231,17 +1249,9 @@ static int ksz8795_switch_init(struct ksz_device *dev) if (!dev->cpu_ports) return -ENODEV; - dev->port_mask = BIT(dev->port_cnt) - 1; - dev->port_mask |= dev->host_mask; - dev->reg_mib_cnt = KSZ8795_COUNTER_NUM; dev->mib_cnt = ARRAY_SIZE(mib_names); - dev->phy_port_cnt = dev->port_cnt - 1; - - dev->cpu_port = dev->port_cnt - 1; - dev->host_mask = BIT(dev->cpu_port); - dev->ports = devm_kzalloc(dev->dev, dev->port_cnt * sizeof(struct ksz_port), GFP_KERNEL); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index a2aa83d82edd..9ab81f903606 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -434,7 +434,7 @@ int ksz_switch_register(struct ksz_device *dev, if (of_property_read_u32(port, "reg", &port_num)) continue; - if (port_num >= dev->port_cnt) + if (!(dev->port_mask & BIT(port_num))) return -EINVAL; of_get_phy_mode(port, &dev->ports[port_num].interface); -- 2.29.2
[PATCH net-next] net: dsa: microchip: Adjust reset release timing to match reference reset circuit
KSZ8794CNX datasheet section 8.0 RESET CIRCUIT describes recommended circuit for interfacing with CPU/FPGA reset consisting of 10k pullup resistor and 10uF capacitor to ground. This circuit takes ~100 mS to rise enough to release the reset. For maximum supply voltage VDDIO=3.3V VIH=2.0V R=10kR C=10uF that is VDDIO - VIH t = R * C * -ln( - ) = 1*0.1*-(-0.93)=0.093 S VDDIO so we need ~95 mS for the reset to really de-assert, and then the original 100uS for the switch itself to come out of reset. Simply msleep() for 100 mS which fits the constraint with a bit of extra space. Fixes: 5b797980908a ("net: dsa: microchip: Implement recommended reset timing") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Jakub Kicinski Cc: Michael Grzeschik Cc: Paul Barker --- drivers/net/dsa/microchip/ksz_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 489963664443..389abfd27770 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -400,7 +400,7 @@ int ksz_switch_register(struct ksz_device *dev, gpiod_set_value_cansleep(dev->reset_gpio, 1); usleep_range(1, 12000); gpiod_set_value_cansleep(dev->reset_gpio, 0); - usleep_range(100, 1000); + msleep(100); } mutex_init(&dev->dev_mutex); -- 2.29.2
[PATCH net-next V2] net: dsa: microchip: Adjust reset release timing to match reference reset circuit
KSZ8794CNX datasheet section 8.0 RESET CIRCUIT describes recommended circuit for interfacing with CPU/FPGA reset consisting of 10k pullup resistor and 10uF capacitor to ground. This circuit takes ~100 ms to rise enough to release the reset. For maximum supply voltage VDDIO=3.3V VIH=2.0V R=10kR C=10uF that is VDDIO - VIH t = R * C * -ln( - ) = 1*0.1*-(-0.93)=0.093 s VDDIO so we need ~95 ms for the reset to really de-assert, and then the original 100us for the switch itself to come out of reset. Simply msleep() for 100 ms which fits the constraint with a bit of extra space. Fixes: 5b797980908a ("net: dsa: microchip: Implement recommended reset timing") Reviewed-by: Florian Fainelli Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Jakub Kicinski Cc: Michael Grzeschik Cc: Paul Barker --- V2: Use lowercase 's' for second --- drivers/net/dsa/microchip/ksz_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 489963664443..389abfd27770 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -400,7 +400,7 @@ int ksz_switch_register(struct ksz_device *dev, gpiod_set_value_cansleep(dev->reset_gpio, 1); usleep_range(1, 12000); gpiod_set_value_cansleep(dev->reset_gpio, 0); - usleep_range(100, 1000); + msleep(100); } mutex_init(&dev->dev_mutex); -- 2.29.2
Re: [PATCH net-next V2] net: dsa: microchip: Adjust reset release timing to match reference reset circuit
On 1/21/21 2:31 AM, Jakub Kicinski wrote: On Wed, 20 Jan 2021 04:05:02 +0100 Marek Vasut wrote: KSZ8794CNX datasheet section 8.0 RESET CIRCUIT describes recommended circuit for interfacing with CPU/FPGA reset consisting of 10k pullup resistor and 10uF capacitor to ground. This circuit takes ~100 ms to rise enough to release the reset. For maximum supply voltage VDDIO=3.3V VIH=2.0V R=10kR C=10uF that is VDDIO - VIH t = R * C * -ln( - ) = 1*0.1*-(-0.93)=0.093 s VDDIO so we need ~95 ms for the reset to really de-assert, and then the original 100us for the switch itself to come out of reset. Simply msleep() for 100 ms which fits the constraint with a bit of extra space. Fixes: 5b797980908a ("net: dsa: microchip: Implement recommended reset timing") Reviewed-by: Florian Fainelli Signed-off-by: Marek Vasut I'm slightly confused whether this is just future proofing or you actually have a board where this matters. The tree is tagged as net-next but there is a Fixes tag which normally indicates net+stable. I have a board where I trigger this problem, that's how I found it. It should be passed to stable too. So the correct tree / tag is "net" ?
[PATCH 2/2] net: ks8851: Register MDIO bus and the internal PHY
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Register MDIO bus so this PHY can be detected and probed by phylib. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner To: netdev@vger.kernel.org --- drivers/net/ethernet/micrel/ks8851.h| 1 + drivers/net/ethernet/micrel/ks8851_common.c | 69 - 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index 2b319e451121..9bed9e024d81 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -403,6 +403,7 @@ struct ks8851_net { struct regulator*vdd_reg; struct regulator*vdd_io; int gpio; + struct mii_bus *mii_bus; void(*lock)(struct ks8851_net *ks, unsigned long *flags); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 6fc7483aea03..c4f5cb9768ef 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -23,6 +23,7 @@ #include #include +#include #include #include "ks8851.h" @@ -983,6 +984,24 @@ static void ks8851_phy_write(struct net_device *dev, } } +static int ks8851_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct ks8851_net *ks = bus->priv; + + if (phy_id != 0) + return 0x; + + return ks8851_phy_read(ks->netdev, phy_id, reg); +} + +static int ks8851_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + struct ks8851_net *ks = bus->priv; + + ks8851_phy_write(ks->netdev, phy_id, reg, val); + return 0; +} + /** * ks8851_read_selftest - read the selftest memory info. * @ks: The device state @@ -1046,6 +1065,42 @@ int ks8851_resume(struct device *dev) } #endif +static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) +{ + struct mii_bus *mii_bus; + int ret; + + mii_bus = mdiobus_alloc(); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "ks8851_eth_mii"; + mii_bus->read = ks8851_mdio_read; + mii_bus->write = ks8851_mdio_write; + mii_bus->priv = ks; + mii_bus->parent = dev; + mii_bus->phy_mask = ~BIT(0); + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + + ret = mdiobus_register(mii_bus); + if (ret) + goto err_mdiobus_register; + + ks->mii_bus = mii_bus; + + return 0; + +err_mdiobus_register: + mdiobus_free(mii_bus); + return ret; +} + +static void ks8851_unregister_mdiobus(struct ks8851_net *ks) +{ + mdiobus_unregister(ks->mii_bus); + mdiobus_free(ks->mii_bus); +} + int ks8851_probe_common(struct net_device *netdev, struct device *dev, int msg_en) { @@ -1104,6 +1159,8 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work); + SET_NETDEV_DEV(netdev, dev); + /* setup EEPROM state */ ks->eeprom.data = ks; ks->eeprom.width = PCI_EEPROM_WIDTH_93C46; @@ -1120,6 +1177,10 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, dev_info(dev, "message enable is %d\n", msg_en); + ret = ks8851_register_mdiobus(ks, dev); + if (ret) + goto err_mdio; + /* set the default message enable */ ks->msg_enable = netif_msg_init(msg_en, NETIF_MSG_DRV | NETIF_MSG_PROBE | @@ -1128,7 +1189,6 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, skb_queue_head_init(&ks->txq); netdev->ethtool_ops = &ks8851_ethtool_ops; - SET_NETDEV_DEV(netdev, dev); dev_set_drvdata(dev, ks); @@ -1156,7 +1216,7 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, ret = register_netdev(netdev); if (ret) { dev_err(dev, "failed to register network device\n"); - goto err_netdev; + goto err_id; } netdev_info(netdev, "revision %d, MAC %pM, IRQ %d, %s EEPROM\n", @@ -1165,8 +1225,9 @@ int ks8851_probe_common(struct net_device *netdev, struct device *dev, return 0; -err_netdev: err_id: + ks8851_unregister_mdiobus(ks); +err_mdio: if (gpio_is_valid(gpio)) gpio_set_value(gpio, 0); regulator_disable(ks->vdd_reg); @@ -1180,6 +1241,8 @@ int
[PATCH 1/2] net: phy: micrel: Add KS8851 PHY support
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Add PHY ID for this KS8851 PHY and use custom PHY ID mask due to the swap. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner To: netdev@vger.kernel.org --- drivers/net/phy/micrel.c | 9 + include/linux/micrel_phy.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 54e0d75203da..ca6da128e37a 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1386,6 +1386,14 @@ static struct phy_driver ksphy_driver[] = { .read_status= ksz8873mll_read_status, .suspend= genphy_suspend, .resume = genphy_resume, +}, { + .phy_id = PHY_ID_KSZ8851, + .phy_id_mask= 0xfff000ff, + .name = "Micrel KSZ8851 Ethernet MAC", + /* PHY_BASIC_FEATURES */ + .config_init= kszphy_config_init, + .suspend= genphy_suspend, + .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ886X, .phy_id_mask= MICREL_PHY_ID_MASK, @@ -1432,6 +1440,7 @@ static struct mdio_device_id __maybe_unused micrel_tbl[] = { { PHY_ID_KSZ8061, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ8081, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ8851, 0xfff000ff }, { PHY_ID_KSZ886X, MICREL_PHY_ID_MASK }, { PHY_ID_LAN8814, MICREL_PHY_ID_MASK }, { } diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h index 416ee6dd2574..1c26e4ac0dc9 100644 --- a/include/linux/micrel_phy.h +++ b/include/linux/micrel_phy.h @@ -29,6 +29,8 @@ #define PHY_ID_KSZ9131 0x00221640 #define PHY_ID_LAN8814 0x00221660 +/* The PHY ID Low/High registers are swapped on KSZ8851 */ +#define PHY_ID_KSZ8851 0x14300022 #define PHY_ID_KSZ886X 0x00221430 #define PHY_ID_KSZ8863 0x00221435 -- 2.29.2
Re: [PATCH 1/2] net: phy: micrel: Add KS8851 PHY support
On 12/30/20 4:43 PM, Andrew Lunn wrote: On Wed, Dec 30, 2020 at 01:53:57PM +0100, Marek Vasut wrote: The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Can you intercept the reads in the KS8851 driver and swap them back again? The mv88e6xxx driver does something similar. The mv88e6393 family of switches have PHYs with the Marvell OUI but no device ID. So the code traps these reads and provides an ID. I would prefer to keep this as-is, since then the PHY driver can match on these swapped IDs and discern the PHY from PHY present in the KS886x switch.
Re: [PATCH 2/2] net: ks8851: Register MDIO bus and the internal PHY
On 12/30/20 5:00 PM, Andrew Lunn wrote: +static int ks8851_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct ks8851_net *ks = bus->priv; + + if (phy_id != 0) + return 0x; + Please check for C45 and return -EOPNOTSUPP. The ks8851_reg_read() does all the register checking already.
Re: [PATCH 1/2] net: phy: micrel: Add KS8851 PHY support
On 1/3/21 5:55 PM, Andrew Lunn wrote: On Sun, Jan 03, 2021 at 01:55:22PM +0100, Marek Vasut wrote: On 12/30/20 4:43 PM, Andrew Lunn wrote: On Wed, Dec 30, 2020 at 01:53:57PM +0100, Marek Vasut wrote: The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Can you intercept the reads in the KS8851 driver and swap them back again? The mv88e6xxx driver does something similar. The mv88e6393 family of switches have PHYs with the Marvell OUI but no device ID. So the code traps these reads and provides an ID. I would prefer to keep this as-is, since then the PHY driver can match on these swapped IDs and discern the PHY from PHY present in the KS886x switch. The problem is, this ID contains an OUI. Well, part of an OUI, the top two bits of the OUI are removed, leaving 22 bits of a 24 bit OUI. These OUIs are assigned to companies, well organisations. If you look at the reversed PHY ID, what are the 4 possible OUIs? Who are they assigned to? Are they ever likely to manufacture a PHY? Are these OUIs used for anything else than identifying the PHY though ?
[PATCH V2 2/2] net: ks8851: Register MDIO bus and the internal PHY
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Register MDIO bus so this PHY can be detected and probed by phylib. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner To: netdev@vger.kernel.org --- V2: - Cast the BIT(0) to u32 to avoid build warnings - Swap PHY ID Hi/Lo registers for MDIO bus access (retain old behavior for MII bus access) - Return -EOPNOTSUPP on read from nonexisting PHY registers --- drivers/net/ethernet/micrel/ks8851.h| 1 + drivers/net/ethernet/micrel/ks8851_common.c | 113 +--- 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index 2b319e451121..9bed9e024d81 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -403,6 +403,7 @@ struct ks8851_net { struct regulator*vdd_reg; struct regulator*vdd_io; int gpio; + struct mii_bus *mii_bus; void(*lock)(struct ks8851_net *ks, unsigned long *flags); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 6fc7483aea03..e0de9c4c98d1 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -23,6 +23,7 @@ #include #include +#include #include #include "ks8851.h" @@ -932,7 +933,25 @@ static int ks8851_phy_reg(int reg) return KS_P1ANLPR; } - return 0x0; + return -EOPNOTSUPP; +} + +static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg) +{ + struct ks8851_net *ks = netdev_priv(dev); + unsigned long flags; + int result; + int ksreg; + + ksreg = ks8851_phy_reg(reg); + if (ksreg < 0) + return ksreg; + + ks8851_lock(ks, &flags); + result = ks8851_rdreg16(ks, ksreg); + ks8851_unlock(ks, &flags); + + return result; } /** @@ -952,20 +971,13 @@ static int ks8851_phy_reg(int reg) */ static int ks8851_phy_read(struct net_device *dev, int phy_addr, int reg) { - struct ks8851_net *ks = netdev_priv(dev); - unsigned long flags; - int ksreg; - int result; + int ret; - ksreg = ks8851_phy_reg(reg); - if (!ksreg) + ret = ks8851_phy_read_common(dev, phy_addr, reg); + if (ret < 0) return 0x0; /* no error return allowed, so use zero */ - ks8851_lock(ks, &flags); - result = ks8851_rdreg16(ks, ksreg); - ks8851_unlock(ks, &flags); - - return result; + return ret; } static void ks8851_phy_write(struct net_device *dev, @@ -976,13 +988,38 @@ static void ks8851_phy_write(struct net_device *dev, int ksreg; ksreg = ks8851_phy_reg(reg); - if (ksreg) { + if (ksreg >= 0) { ks8851_lock(ks, &flags); ks8851_wrreg16(ks, ksreg, value); ks8851_unlock(ks, &flags); } } +static int ks8851_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct ks8851_net *ks = bus->priv; + int ret; + + if (phy_id != 0) + return -EOPNOTSUPP; + + /* KS8851 PHY ID registers are swapped in HW, swap them back. */ + if (reg == MII_PHYSID1) + reg = MII_PHYSID2; + else if (reg == MII_PHYSID2) + reg = MII_PHYSID1; + + return ks8851_phy_read_common(ks->netdev, phy_id, reg); +} + +static int ks8851_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + struct ks8851_net *ks = bus->priv; + + ks8851_phy_write(ks->netdev, phy_id, reg, val); + return 0; +} + /** * ks8851_read_selftest - read the selftest memory info. * @ks: The device state @@ -1046,6 +1083,42 @@ int ks8851_resume(struct device *dev) } #endif +static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) +{ + struct mii_bus *mii_bus; + int ret; + + mii_bus = mdiobus_alloc(); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "ks8851_eth_mii"; + mii_bus->read = ks8851_mdio_read; + mii_bus->write = ks8851_mdio_write; + mii_bus->priv = ks; + mii_bus->parent = dev; + mii_bus->phy_mask = ~((u32)BIT(0)); + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + + ret = mdiobus_register(mii_bus); + if (ret) + goto err_mdiobus_register; + + ks->mii_bus = mii_bus; + + return 0; + +err_mdiobus_register: + mdiobus_f
[PATCH V2 1/2] net: phy: micrel: Add KS8851 PHY support
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, including the PHY ID Low/High registers swap, which is present both in the MAC and the switch. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner To: netdev@vger.kernel.org --- V2: Merge the KSZ8851 and KS886X entries, as those PHYs cannot be discerned --- drivers/net/phy/micrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 54e0d75203da..39c7c786a912 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1389,7 +1389,7 @@ static struct phy_driver ksphy_driver[] = { }, { .phy_id = PHY_ID_KSZ886X, .phy_id_mask= MICREL_PHY_ID_MASK, - .name = "Micrel KSZ886X Switch", + .name = "Micrel KSZ8851 Ethernet MAC or KSZ886X Switch", /* PHY_BASIC_FEATURES */ .config_init= kszphy_config_init, .suspend= genphy_suspend, -- 2.29.2
[PATCH net-next V3 0/2] net: ks8851: Add KS8851 PHY support
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, including the PHY ID Low/High registers swap, which is present both in the MAC and the switch. Marek Vasut (2): net: phy: micrel: Add KS8851 PHY support net: ks8851: Register MDIO bus and the internal PHY drivers/net/ethernet/micrel/ks8851.h| 2 + drivers/net/ethernet/micrel/ks8851_common.c | 112 +--- drivers/net/phy/micrel.c| 2 +- 3 files changed, 99 insertions(+), 17 deletions(-) Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner -- 2.29.2
[PATCH net-next V3 1/2] net: phy: micrel: Add KS8851 PHY support
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, including the PHY ID Low/High registers swap, which is present both in the MAC and the switch. Reviewed-by: Andrew Lunn Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner --- V2: Merge the KSZ8851 and KS886X entries, as those PHYs cannot be discerned V3: Add RB from Andrew --- drivers/net/phy/micrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 54e0d75203da..39c7c786a912 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1389,7 +1389,7 @@ static struct phy_driver ksphy_driver[] = { }, { .phy_id = PHY_ID_KSZ886X, .phy_id_mask= MICREL_PHY_ID_MASK, - .name = "Micrel KSZ886X Switch", + .name = "Micrel KSZ8851 Ethernet MAC or KSZ886X Switch", /* PHY_BASIC_FEATURES */ .config_init= kszphy_config_init, .suspend= genphy_suspend, -- 2.29.2
[PATCH net-next V3 2/2] net: ks8851: Register MDIO bus and the internal PHY
The KS8851 has a reduced internal PHY, which is accessible through its registers at offset 0xe4. The PHY is compatible with KS886x PHY present in Micrel switches, except the PHY ID Low/High registers are swapped. Register MDIO bus so this PHY can be detected and probed by phylib. Reviewed-by: Andrew Lunn Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner --- V2: - Cast the BIT(0) to u32 to avoid build warnings - Swap PHY ID Hi/Lo registers for MDIO bus access (retain old behavior for MII bus access) - Return -EOPNOTSUPP on read from nonexisting PHY registers V3: - Add RB from Andrew - Drop unused ret variable from ks8851_mdio_read() - Document new mii_bus entry in ks8851_net {} --- drivers/net/ethernet/micrel/ks8851.h| 2 + drivers/net/ethernet/micrel/ks8851_common.c | 112 +--- 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index 2b319e451121..e2eb0caeac82 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -358,6 +358,7 @@ union ks8851_tx_hdr { * @vdd_reg: Optional regulator supplying the chip * @vdd_io: Optional digital power supply for IO * @gpio: Optional reset_n gpio + * @mii_bus: Pointer to MII bus structure * @lock: Bus access lock callback * @unlock: Bus access unlock callback * @rdreg16: 16bit register read callback @@ -403,6 +404,7 @@ struct ks8851_net { struct regulator*vdd_reg; struct regulator*vdd_io; int gpio; + struct mii_bus *mii_bus; void(*lock)(struct ks8851_net *ks, unsigned long *flags); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 6fc7483aea03..058fd99bd483 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -23,6 +23,7 @@ #include #include +#include #include #include "ks8851.h" @@ -932,7 +933,25 @@ static int ks8851_phy_reg(int reg) return KS_P1ANLPR; } - return 0x0; + return -EOPNOTSUPP; +} + +static int ks8851_phy_read_common(struct net_device *dev, int phy_addr, int reg) +{ + struct ks8851_net *ks = netdev_priv(dev); + unsigned long flags; + int result; + int ksreg; + + ksreg = ks8851_phy_reg(reg); + if (ksreg < 0) + return ksreg; + + ks8851_lock(ks, &flags); + result = ks8851_rdreg16(ks, ksreg); + ks8851_unlock(ks, &flags); + + return result; } /** @@ -952,20 +971,13 @@ static int ks8851_phy_reg(int reg) */ static int ks8851_phy_read(struct net_device *dev, int phy_addr, int reg) { - struct ks8851_net *ks = netdev_priv(dev); - unsigned long flags; - int ksreg; - int result; + int ret; - ksreg = ks8851_phy_reg(reg); - if (!ksreg) + ret = ks8851_phy_read_common(dev, phy_addr, reg); + if (ret < 0) return 0x0; /* no error return allowed, so use zero */ - ks8851_lock(ks, &flags); - result = ks8851_rdreg16(ks, ksreg); - ks8851_unlock(ks, &flags); - - return result; + return ret; } static void ks8851_phy_write(struct net_device *dev, @@ -976,13 +988,37 @@ static void ks8851_phy_write(struct net_device *dev, int ksreg; ksreg = ks8851_phy_reg(reg); - if (ksreg) { + if (ksreg >= 0) { ks8851_lock(ks, &flags); ks8851_wrreg16(ks, ksreg, value); ks8851_unlock(ks, &flags); } } +static int ks8851_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct ks8851_net *ks = bus->priv; + + if (phy_id != 0) + return -EOPNOTSUPP; + + /* KS8851 PHY ID registers are swapped in HW, swap them back. */ + if (reg == MII_PHYSID1) + reg = MII_PHYSID2; + else if (reg == MII_PHYSID2) + reg = MII_PHYSID1; + + return ks8851_phy_read_common(ks->netdev, phy_id, reg); +} + +static int ks8851_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + struct ks8851_net *ks = bus->priv; + + ks8851_phy_write(ks->netdev, phy_id, reg, val); + return 0; +} + /** * ks8851_read_selftest - read the selftest memory info. * @ks: The device state @@ -1046,6 +1082,42 @@ int ks8851_resume(struct device *dev) } #endif +static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) +{ + struct mii_bus *mii_bus; + int ret; + + mii_bus = mdiobus_alloc(); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "ks8851_eth_mii"; + mii_bus->read = ks8851_mdio_read;
[PATCH] net: phy: Trigger link_change_notify on PHY_HALTED
In case the PHY transitions to PHY_HALTED state in phy_stop(), the link_change_notify callback is not triggered. That's because the phydev->state = PHY_HALTED in phy_stop() is assigned first, and phy_state_machine() is called afterward. For phy_state_machine(), no state transition happens, because old_state = PHY_HALTED and phy_dev->state = PHY_HALTED. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: David S. Miller Cc: Heiner Kallweit --- drivers/net/phy/phy.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 45f75533c47c..fca8c3eebc5d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1004,6 +1004,7 @@ EXPORT_SYMBOL(phy_free_interrupt); void phy_stop(struct phy_device *phydev) { struct net_device *dev = phydev->attached_dev; + enum phy_state old_state; if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) { WARN(1, "called from state %s\n", @@ -1021,8 +1022,17 @@ void phy_stop(struct phy_device *phydev) if (phydev->sfp_bus) sfp_upstream_stop(phydev->sfp_bus); + old_state = phydev->state; phydev->state = PHY_HALTED; + if (old_state != phydev->state) { + phydev_err(phydev, "PHY state change %s -> %s\n", + phy_state_to_str(old_state), + phy_state_to_str(phydev->state)); + if (phydev->drv && phydev->drv->link_change_notify) + phydev->drv->link_change_notify(phydev); + } + mutex_unlock(&phydev->lock); phy_state_machine(&phydev->state_queue.work); -- 2.29.2
[PATCH] [RFC] net: phy: smsc: Add magnetics VIO regulator support
Add support for controlling regulator powering the magnetics. In case the interface is down, it is possible to save considerable power by turning the regulator supplying the magnetics off. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: David S. Miller Cc: Heiner Kallweit --- drivers/net/phy/smsc.c | 24 +++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 33372756a451..edc2bd7d8100 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include /* Vendor-specific PHY Definitions */ @@ -46,6 +49,7 @@ static struct smsc_hw_stat smsc_hw_stats[] = { struct smsc_phy_priv { bool energy_enable; struct clk *refclk; + struct regulator *vddio; }; static int smsc_phy_ack_interrupt(struct phy_device *phydev) @@ -288,6 +292,20 @@ static void smsc_get_stats(struct phy_device *phydev, data[i] = smsc_get_stat(phydev, i); } +static void smsc_link_change_notify(struct phy_device *phydev) +{ + struct smsc_phy_priv *priv = phydev->priv; + + if (!priv->vddio) + return; + + if (phydev->state == PHY_HALTED) + regulator_disable(priv->vddio); + + if (phydev->state == PHY_NOLINK) + regulator_enable(priv->vddio); +} + static void smsc_phy_remove(struct phy_device *phydev) { struct smsc_phy_priv *priv = phydev->priv; @@ -309,6 +327,10 @@ static int smsc_phy_probe(struct phy_device *phydev) priv->energy_enable = true; + priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev, "vddio"); + if (IS_ERR(priv->vddio)) + return PTR_ERR(priv->vddio); + if (of_property_read_bool(of_node, "smsc,disable-energy-detect")) priv->energy_enable = false; @@ -432,7 +454,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8710/LAN8720", /* PHY_BASIC_FEATURES */ - + .link_change_notify = smsc_link_change_notify, .probe = smsc_phy_probe, .remove = smsc_phy_remove, -- 2.29.2
Re: [PATCH] [RFC] net: phy: smsc: Add magnetics VIO regulator support
On 1/5/21 6:38 PM, Andrew Lunn wrote: +static void smsc_link_change_notify(struct phy_device *phydev) +{ + struct smsc_phy_priv *priv = phydev->priv; + + if (!priv->vddio) + return; + + if (phydev->state == PHY_HALTED) + regulator_disable(priv->vddio); + + if (phydev->state == PHY_NOLINK) + regulator_enable(priv->vddio); NOLINK is an interesting choice. Could you explain that please. It's the first state after interface is up. I fear this is not going to be very robust to state machine changes. And since it is hidden away in a driver, it is going to be forgotten about. You might want to think about making it more robust. I marked the patch as RFC because I would like input on how to implement this properly. Note that since the regulator supplies the magnetics, which might be shared between multiple ports with different PHYs, I don't think this code should even be in the PHY driver, but somewhere else -- but I don't know where.
Re: [PATCH] [RFC] net: phy: smsc: Add magnetics VIO regulator support
On 1/5/21 8:03 PM, Andrew Lunn wrote: On Tue, Jan 05, 2021 at 06:53:48PM +0100, Marek Vasut wrote: On 1/5/21 6:38 PM, Andrew Lunn wrote: +static void smsc_link_change_notify(struct phy_device *phydev) +{ + struct smsc_phy_priv *priv = phydev->priv; + + if (!priv->vddio) + return; + + if (phydev->state == PHY_HALTED) + regulator_disable(priv->vddio); + + if (phydev->state == PHY_NOLINK) + regulator_enable(priv->vddio); NOLINK is an interesting choice. Could you explain that please. It's the first state after interface is up. No, not really. phy_start() actually sets it to PHY_UP. When the state machine runs, it kicks off auto-neg and immediately reads the link state. If the link is down, it transitions to PHY_NOLINK, at which point this code will enable the regulator. I fear this is not going to be very robust to state machine changes. And since it is hidden away in a driver, it is going to be forgotten about. You might want to think about making it more robust. I marked the patch as RFC because I would like input on how to implement this properly. Note that since the regulator supplies the magnetics, which might be shared between multiple ports with different PHYs, I don't think this code should even be in the PHY driver, but somewhere else -- but I don't know where. Being shared should not be a problem. The regulator API does reference counting. Any one driver turning the regulator on will enable it. But it will not be turned off until all the drivers disable it after enabling it. But that also means you need to balance the calls to regulator_enable() and regulator_disable(). If for whatever reason this function is called for PHY_HALTED more times than for PHY_NOLINK, the counter can go negative, and bad things would happen. So i would actually had a bool to smsc_phy_priv indicating if the regulator has been enabled. And for each phydev->state, decide if the regulator should be enabled, check if it is enabled according to the bool, and enable it is not. Same with states which indicate it should be disabled. The code is then not dependent on specific transitions, but on actual states. That should be more robust to changes. You also need to think about this regulator being shared. Say some other PHY has enabled the regulator. phy_start() might be able to skip PHY_NOLINK state and so this PHY never calls regulator_enable(). If that other PHY is then configured down, it will disable the regulator, and this PHY looses link. That probably is enough for this PHY to re-enable the regulator, but it is not ideal. I think you are completely missing the point, the regulator is just an implementation detail. I am more interested in the implementation itself, which I suspect should not even be in the PHY driver, but rather somewhere closer to the core (where?), because the supply to magnetics is not part of the PHY, any PHY can be used with magnetics which need a regulator.
[PATCH net-next] net: ks8851: Select PHYLIB and MICREL_PHY in Kconfig
The PHYLIB must be selected to provide mdiobus_*() functions, and the MICREL_PHY is necessary too, as that is the only possible PHY attached to the KS8851 (it is the internal PHY). Fixes: ef3631220d2b ("net: ks8851: Register MDIO bus and the internal PHY") Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner --- drivers/net/ethernet/micrel/Kconfig | 4 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig index 42bc014136fe..93df3049cdc0 100644 --- a/drivers/net/ethernet/micrel/Kconfig +++ b/drivers/net/ethernet/micrel/Kconfig @@ -31,6 +31,8 @@ config KS8851 select MII select CRC32 select EEPROM_93CX6 + select PHYLIB + select MICREL_PHY help SPI driver for Micrel KS8851 SPI attached network chip. @@ -40,6 +42,8 @@ config KS8851_MLL select MII select CRC32 select EEPROM_93CX6 + select PHYLIB + select MICREL_PHY help This platform driver is for Micrel KS8851 Address/data bus multiplexed network chip. -- 2.29.2
[PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
Unless the internal PHY is connected and started, the phylib will not poll the PHY for state and produce state updates. Connect the PHY and start/stop it. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Heiner Kallweit Cc: Lukas Wunner --- drivers/net/ethernet/micrel/ks8851.h| 2 ++ drivers/net/ethernet/micrel/ks8851_common.c | 28 + 2 files changed, 30 insertions(+) diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h index e2eb0caeac82..ef13929036cf 100644 --- a/drivers/net/ethernet/micrel/ks8851.h +++ b/drivers/net/ethernet/micrel/ks8851.h @@ -359,6 +359,7 @@ union ks8851_tx_hdr { * @vdd_io: Optional digital power supply for IO * @gpio: Optional reset_n gpio * @mii_bus: Pointer to MII bus structure + * @phy_dev: Pointer to PHY device structure * @lock: Bus access lock callback * @unlock: Bus access unlock callback * @rdreg16: 16bit register read callback @@ -405,6 +406,7 @@ struct ks8851_net { struct regulator*vdd_io; int gpio; struct mii_bus *mii_bus; + struct phy_device *phy_dev; void(*lock)(struct ks8851_net *ks, unsigned long *flags); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 058fd99bd483..a3716fd2d858 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -432,6 +432,11 @@ static void ks8851_flush_tx_work(struct ks8851_net *ks) ks->flush_tx_work(ks); } +static void ks8851_handle_link_change(struct net_device *net) +{ + phy_print_status(net->phydev); +} + /** * ks8851_net_open - open network device * @dev: The network device being opened. @@ -445,11 +450,22 @@ static int ks8851_net_open(struct net_device *dev) unsigned long flags; int ret; + ret = phy_connect_direct(ks->netdev, ks->phy_dev, +&ks8851_handle_link_change, +PHY_INTERFACE_MODE_INTERNAL); + if (ret) { + netdev_err(dev, "failed to attach PHY\n"); + return ret; + } + + phy_attached_info(ks->phy_dev); + ret = request_threaded_irq(dev->irq, NULL, ks8851_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev->name, ks); if (ret < 0) { netdev_err(dev, "failed to get irq\n"); + phy_disconnect(ks->phy_dev); return ret; } @@ -507,6 +523,7 @@ static int ks8851_net_open(struct net_device *dev) netif_dbg(ks, ifup, ks->netdev, "network device up\n"); ks8851_unlock(ks, &flags); + phy_start(ks->phy_dev); mii_check_link(&ks->mii); return 0; } @@ -528,6 +545,9 @@ static int ks8851_net_stop(struct net_device *dev) netif_stop_queue(dev); + phy_stop(ks->phy_dev); + phy_disconnect(ks->phy_dev); + ks8851_lock(ks, &flags); /* turn off the IRQs and ack any outstanding */ ks8851_wrreg16(ks, KS_IER, 0x); @@ -1084,6 +1104,7 @@ int ks8851_resume(struct device *dev) static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) { + struct phy_device *phy_dev; struct mii_bus *mii_bus; int ret; @@ -1103,10 +1124,17 @@ static int ks8851_register_mdiobus(struct ks8851_net *ks, struct device *dev) if (ret) goto err_mdiobus_register; + phy_dev = phy_find_first(mii_bus); + if (!phy_dev) + goto err_find_phy; + ks->mii_bus = mii_bus; + ks->phy_dev = phy_dev; return 0; +err_find_phy: + mdiobus_unregister(mii_bus); err_mdiobus_register: mdiobus_free(mii_bus); return ret; -- 2.29.2
Re: [PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
On 1/11/21 2:26 PM, Heiner Kallweit wrote: [...] LGTM. When having a brief look at the driver I stumbled across two things: 1. Do MAC/PHY support any pause mode? Then a call to phy_support_(a)sym_pause() would be missing. https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ8851-16MLL-Single-Port-Ethernet-MAC-Controller-with-8-Bit-or-16-Bit-Non-PCI-Interface-DS2357B.pdf page 64 https://www.mouser.com/datasheet/2/268/ksz8851-16mll_ds-776208.pdf page 65 The later is more complete. Apparently it does support pause. 2. Don't have the datasheet, but IRQ_LCI seems to be the link change interrupt. So far it's ignored by the driver. You could configure it and use phy_mac_interrupt() to operate the internal PHY in interrupt mode. That's only for link state change, shouldn't the PHY interrupt trigger on other things as well ?
Re: [PATCH net-next] net: ks8851: Connect and start/stop the internal PHY
On 1/11/21 2:50 PM, Heiner Kallweit wrote: On 11.01.2021 14:38, Marek Vasut wrote: On 1/11/21 2:26 PM, Heiner Kallweit wrote: [...] LGTM. When having a brief look at the driver I stumbled across two things: 1. Do MAC/PHY support any pause mode? Then a call to    phy_support_(a)sym_pause() would be missing. https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ8851-16MLL-Single-Port-Ethernet-MAC-Controller-with-8-Bit-or-16-Bit-Non-PCI-Interface-DS2357B.pdf page 64 https://www.mouser.com/datasheet/2/268/ksz8851-16mll_ds-776208.pdf page 65 The later is more complete. Apparently it does support pause. Based on the datasheet, does it support sym or asym pause ? 2. Don't have the datasheet, but IRQ_LCI seems to be the link change    interrupt. So far it's ignored by the driver. You could configure    it and use phy_mac_interrupt() to operate the internal PHY in    interrupt mode. That's only for link state change, shouldn't the PHY interrupt trigger on other things as well ? No, it's sufficient if the interrupt can signal link state change. In r8169 I have exactly that case. I'll do that in a subsequent patch, once I verify it works as it should.
[PATCH 1/2] rsi: Move card interrupt handling to RX thread
The interrupt handling of the RS911x is particularly heavy. For each RX packet, the card does three SDIO transactions, one to read interrupt status register, one to RX buffer length, one to read the RX packet(s). This translates to ~330 uS per one cycle of interrupt handler. In case there is more incoming traffic, this will be more. The drivers/mmc/core/sdio_irq.c has the following comment, quote "Just like traditional hard IRQ handlers, we expect SDIO IRQ handlers to be quick and to the point, so that the holding of the host lock does not cover too much work that doesn't require that lock to be held." The RS911x interrupt handler does not fit that. This patch therefore changes it such that the entire IRQ handler is moved to the RX thread instead, and the interrupt handler only wakes the RX thread. This is OK, because the interrupt handler only does things which can also be done in the RX thread, that is, it checks for firmware loading error(s), it checks buffer status, it checks whether a packet arrived and if so, reads out the packet and passes it to network stack. Moreover, this change permits removal of a code which allocated an skbuff only to get 4-byte-aligned buffer, read up to 8kiB of data into the skbuff, queue this skbuff into local private queue, then in RX thread, this buffer is dequeued, the data in the skbuff as passed to the RSI driver core, and the skbuff is deallocated. All this is replaced by directly calling the RSI driver core with local buffer. Signed-off-by: Marek Vasut Cc: Angus Ainslie Cc: David S. Miller Cc: Jakub Kicinski Cc: Kalle Valo Cc: Lee Jones Cc: Martin Kepplinger Cc: Sebastian Krzyszkowiak Cc: Siva Rebbagondla Cc: linux-wirel...@vger.kernel.org Cc: netdev@vger.kernel.org --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 6 +-- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 52 ++--- drivers/net/wireless/rsi/rsi_sdio.h | 8 +--- 3 files changed, 15 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 78ad605081ae..d81874eee4b3 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -153,9 +153,7 @@ static void rsi_handle_interrupt(struct sdio_func *function) if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED) return; - dev->sdio_irq_task = current; - rsi_interrupt_handler(adapter); - dev->sdio_irq_task = NULL; + rsi_set_event(&dev->rx_thread.event); } /** @@ -1058,8 +1056,6 @@ static int rsi_probe(struct sdio_func *pfunction, rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); goto fail_kill_thread; } - skb_queue_head_init(&sdev->rx_q.head); - sdev->rx_q.num_rx_pkts = 0; sdio_claim_host(pfunction); if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 7825c9a889d3..23e709aabd1f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -60,39 +60,20 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) return status; } +static void rsi_rx_handler(struct rsi_hw *adapter); + void rsi_sdio_rx_thread(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; - struct sk_buff *skb; - int status; do { rsi_wait_event(&sdev->rx_thread.event, EVENT_WAIT_FOREVER); rsi_reset_event(&sdev->rx_thread.event); + rsi_rx_handler(adapter); + } while (!atomic_read(&sdev->rx_thread.thread_done)); - while (true) { - if (atomic_read(&sdev->rx_thread.thread_done)) - goto out; - - skb = skb_dequeue(&sdev->rx_q.head); - if (!skb) - break; - if (sdev->rx_q.num_rx_pkts > 0) - sdev->rx_q.num_rx_pkts--; - status = rsi_read_pkt(common, skb->data, skb->len); - if (status) { - rsi_dbg(ERR_ZONE, "Failed to read the packet\n"); - dev_kfree_skb(skb); - break; - } - dev_kfree_skb(skb); - } - } while (1); - -out: rsi_dbg(INFO_ZONE, "%s: Terminated SDIO RX thread\n", __func__); - skb_queue_purge(&sdev->rx_q.head); atomic_inc(&sdev->rx_thread.thread_done); complete_and_exit(&sdev->rx_thread.completion, 0);
[PATCH 2/2] rsi: Clean up loop in the interrupt handler
The inner do { ... } while loop is completely useless, all it does is iterate over a switch-case statement, one bit at a time. This can easily be replaced by simple if (status & bit) { ... } tests for each bit. No functional change. Signed-off-by: Marek Vasut Cc: Angus Ainslie Cc: David S. Miller Cc: Jakub Kicinski Cc: Kalle Valo Cc: Lee Jones Cc: Martin Kepplinger Cc: Sebastian Krzyszkowiak Cc: Siva Rebbagondla Cc: linux-wirel...@vger.kernel.org Cc: netdev@vger.kernel.org --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 121 ++-- 1 file changed, 58 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 23e709aabd1f..8ace1874e5cb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -236,7 +236,6 @@ static void rsi_rx_handler(struct rsi_hw *adapter) struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; int status; - enum sdio_interrupt_type isr_type; u8 isr_status = 0; u8 fw_status = 0; @@ -267,73 +266,69 @@ static void rsi_rx_handler(struct rsi_hw *adapter) __func__, isr_status, (1 << MSDU_PKT_PENDING), (1 << FW_ASSERT_IND)); - do { - RSI_GET_SDIO_INTERRUPT_TYPE(isr_status, isr_type); - - switch (isr_type) { - case BUFFER_AVAILABLE: - status = rsi_sdio_check_buffer_status(adapter, - 0); - if (status < 0) - rsi_dbg(ERR_ZONE, - "%s: Failed to check buffer status\n", - __func__); - rsi_sdio_ack_intr(common->priv, - (1 << PKT_BUFF_AVAILABLE)); - rsi_set_event(&common->tx_thread.event); - - rsi_dbg(ISR_ZONE, - "%s: ==> BUFFER_AVAILABLE <==\n", - __func__); - dev->buff_status_updated = true; - break; - - case FIRMWARE_ASSERT_IND: + if (isr_status & BIT(PKT_BUFF_AVAILABLE)) { + status = rsi_sdio_check_buffer_status(adapter, 0); + if (status < 0) rsi_dbg(ERR_ZONE, - "%s: ==> FIRMWARE Assert <==\n", + "%s: Failed to check buffer status\n", __func__); - status = rsi_sdio_read_register(common->priv, + rsi_sdio_ack_intr(common->priv, + BIT(PKT_BUFF_AVAILABLE)); + rsi_set_event(&common->tx_thread.event); + + rsi_dbg(ISR_ZONE, "%s: ==> BUFFER_AVAILABLE <==\n", + __func__); + dev->buff_status_updated = true; + + isr_status &= ~BIT(PKT_BUFF_AVAILABLE); + } + + if (isr_status & BIT(FW_ASSERT_IND)) { + rsi_dbg(ERR_ZONE, "%s: ==> FIRMWARE Assert <==\n", + __func__); + status = rsi_sdio_read_register(common->priv, SDIO_FW_STATUS_REG, &fw_status); - if (status) { - rsi_dbg(ERR_ZONE, - "%s: Failed to read f/w reg\n", - __func__); - } else { - rsi_dbg(ERR_ZONE, - "%s: Firmware Status is 0x%x\n", - __func__ , fw_status); - rsi_sdio_ack_intr(common->priv, - (1 << FW_ASSERT_IND)); - } - - common->fsm_state = FSM_CARD_NOT_READY; - break; - - case MSDU_PACKET_PENDING: - rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n"); - d
Re: [PATCH 1/2] rsi: Move card interrupt handling to RX thread
On 11/4/20 4:21 PM, Martin Kepplinger wrote: On 03.11.20 19:09, Marek Vasut wrote: The interrupt handling of the RS911x is particularly heavy. For each RX packet, the card does three SDIO transactions, one to read interrupt status register, one to RX buffer length, one to read the RX packet(s). This translates to ~330 uS per one cycle of interrupt handler. In case there is more incoming traffic, this will be more. The drivers/mmc/core/sdio_irq.c has the following comment, quote "Just like traditional hard IRQ handlers, we expect SDIO IRQ handlers to be quick and to the point, so that the holding of the host lock does not cover too much work that doesn't require that lock to be held." The RS911x interrupt handler does not fit that. This patch therefore changes it such that the entire IRQ handler is moved to the RX thread instead, and the interrupt handler only wakes the RX thread. This is OK, because the interrupt handler only does things which can also be done in the RX thread, that is, it checks for firmware loading error(s), it checks buffer status, it checks whether a packet arrived and if so, reads out the packet and passes it to network stack. Moreover, this change permits removal of a code which allocated an skbuff only to get 4-byte-aligned buffer, read up to 8kiB of data into the skbuff, queue this skbuff into local private queue, then in RX thread, this buffer is dequeued, the data in the skbuff as passed to the RSI driver core, and the skbuff is deallocated. All this is replaced by directly calling the RSI driver core with local buffer. Signed-off-by: Marek Vasut Cc: Angus Ainslie Cc: David S. Miller Cc: Jakub Kicinski Cc: Kalle Valo Cc: Lee Jones Cc: Martin Kepplinger Cc: Sebastian Krzyszkowiak Cc: Siva Rebbagondla Cc: linux-wirel...@vger.kernel.org Cc: netdev@vger.kernel.org --- Â drivers/net/wireless/rsi/rsi_91x_sdio.c |Â 6 +-- Â drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 52 ++--- Â drivers/net/wireless/rsi/rsi_sdio.h |Â 8 +--- Â 3 files changed, 15 insertions(+), 51 deletions(-) hi Marek, Hi, I'm running this without problems, so feel free to add Tested-by: Martin Kepplinger Thank you. Do you observe better RX performance ? For me, without this patch, iperf3 -R did ~4 Mbit/s on iwlwifi AP running hostap in 802.11n mode (wpa2 tkip), with this patch I see 40 Mbit/s (10x better, yes). However, the poor rx performance did depend on the kernel configuration (HZ, preemption settings) before, now it does not.
[PATCH] rsi: Use resume_noirq for SDIO
The rsi_resume() does access the bus to enable interrupts on the RSI SDIO WiFi card, however when calling sdio_claim_host() in the resume path, it is possible the bus is already claimed and sdio_claim_host() spins indefinitelly. Enable the SDIO card interrupts in resume_noirq instead to prevent anything else from claiming the SDIO bus first. Fixes: 20db07332736 ("rsi: sdio suspend and resume support") Signed-off-by: Marek Vasut Cc: Amitkumar Karwar Cc: Angus Ainslie Cc: David S. Miller Cc: Jakub Kicinski Cc: Kalle Valo Cc: Karun Eagalapati Cc: Martin Kepplinger Cc: Sebastian Krzyszkowiak Cc: Siva Rebbagondla Cc: netdev@vger.kernel.org Cc: sta...@vger.kernel.org --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 122174fca672..8465a4ee9b61 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1513,7 +1513,7 @@ static int rsi_restore(struct device *dev) } static const struct dev_pm_ops rsi_pm_ops = { .suspend = rsi_suspend, - .resume = rsi_resume, + .resume_noirq = rsi_resume, .freeze = rsi_freeze, .thaw = rsi_thaw, .restore = rsi_restore, -- 2.30.2
Re: [PATCH] [5.8 regression] net: ks8851: fix link error
On 1/25/21 1:19 PM, Arnd Bergmann wrote: From: Arnd Bergmann An object file cannot be built for both loadable module and built-in use at the same time: arm-linux-gnueabi-ld: drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': ks8851_common.c:(.text+0xf80): undefined reference to `__this_module' Change the ks8851_common code to be a standalone module instead, and use Makefile logic to ensure this is built-in if at least one of its two users is. Fixes: 797047f875b5 ("net: ks8851: Implement Parallel bus operations") Signed-off-by: Arnd Bergmann --- Marek sent two other patches to address the problem: https://lore.kernel.org/netdev/20210116164828.40545-1-ma...@denx.de/ https://lore.kernel.org/netdev/20210115134239.126152-1-ma...@denx.de/ My version is what I applied locally to my randconfig tree, and I think this is the cleanest solution. If this version works for all the configuration combinations, then that's perfect, thanks.
Re: [PATCH AUTOSEL 5.10 050/217] rsi: Fix TX EAPOL packet handling against iwlwifi AP
On 12/23/20 3:13 AM, Sasha Levin wrote: Hello Sasha, From: Marek Vasut [ Upstream commit 65277100caa2f2c62b6f3c4648b90d6f0435f3bc ] In case RSI9116 SDIO WiFi operates in STA mode against Intel 9260 in AP mode, the association fails. The former is using wpa_supplicant during association, the later is set up using hostapd: [...] Was this patch possibly missed from 5.10.y ? Also, while at it, I think it might make sense to pick the following two patches as well, they dramatically reduce interrupt rate of the RSI WiFi device, so it stops overloading lower-end devices: 287431463e786 ("rsi: Move card interrupt handling to RX thread") abd131a19f6b8 ("rsi: Clean up loop in the interrupt handler")
Re: [PATCH AUTOSEL 5.10 050/217] rsi: Fix TX EAPOL packet handling against iwlwifi AP
On 3/4/21 9:47 PM, Sasha Levin wrote: On Tue, Mar 02, 2021 at 08:25:49PM +0100, Marek Vasut wrote: On 12/23/20 3:13 AM, Sasha Levin wrote: Hello Sasha, From: Marek Vasut [ Upstream commit 65277100caa2f2c62b6f3c4648b90d6f0435f3bc ] In case RSI9116 SDIO WiFi operates in STA mode against Intel 9260 in AP mode, the association fails. The former is using wpa_supplicant during association, the later is set up using hostapd: [...] Was this patch possibly missed from 5.10.y ? I'm not sure what happened there, but I can queue it up. Thank you Also, while at it, I think it might make sense to pick the following two patches as well, they dramatically reduce interrupt rate of the RSI WiFi device, so it stops overloading lower-end devices: 287431463e786 ("rsi: Move card interrupt handling to RX thread") And this one too. Thanks abd131a19f6b8 ("rsi: Clean up loop in the interrupt handler") But not this one, it looks like just a cleanup. Why is it needed? Now I got confused, yes, please skip abd131a19f6b8, thanks for spotting it. (I still have one more patch for the RSI wifi which I need to send out, but that's for later)
[PATCH] net: dsa: microchip: Use gpiod_set_value_cansleep()
Replace gpiod_set_value() with gpiod_set_value_cansleep(), as the switch reset GPIO can be connected to e.g. I2C GPIO expander and it is perfectly fine for the kernel to sleep for a bit in ksz_switch_register(). Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Linus Walleij Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 4f6648d5ac8b..bc81806dd75e 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -436,9 +436,9 @@ int ksz_switch_register(struct ksz_device *dev, return PTR_ERR(dev->reset_gpio); if (dev->reset_gpio) { - gpiod_set_value(dev->reset_gpio, 1); + gpiod_set_value_cansleep(dev->reset_gpio, 1); mdelay(10); - gpiod_set_value(dev->reset_gpio, 0); + gpiod_set_value_cansleep(dev->reset_gpio, 0); } mutex_init(&dev->dev_mutex); -- 2.20.1
[PATCH] net: ethernet: ti: cpsw: Assign OF node to slave devices
Assign OF node to CPSW slave devices, otherwise it is not possible to bind e.g. DSA switch to them. Without this patch, the DSA code tries to find the ethernet device by OF match, but fails to do so because the slave device has NULL OF node. Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Ivan Khoronzhuk --- drivers/net/ethernet/ti/cpsw.c | 3 +++ drivers/net/ethernet/ti/cpsw_priv.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 7bdd287074fc..c39790e21276 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2179,6 +2179,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, return ret; } + slave_data->slave_node = slave_node; slave_data->phy_node = of_parse_phandle(slave_node, "phy-handle", 0); parp = of_get_property(slave_node, "phy_id", &lenp); @@ -2329,6 +2330,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv) /* register the network device */ SET_NETDEV_DEV(ndev, cpsw->dev); + ndev->dev.of_node = cpsw->slaves[1].data->slave_node; ret = register_netdev(ndev); if (ret) dev_err(cpsw->dev, "cpsw: error registering net device\n"); @@ -2506,6 +2508,7 @@ static int cpsw_probe(struct platform_device *pdev) /* register the network device */ SET_NETDEV_DEV(ndev, dev); + ndev->dev.of_node = cpsw->slaves[0].data->slave_node; ret = register_netdev(ndev); if (ret) { dev_err(dev, "error registering net device\n"); diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 04795b97ee71..e32f11da2dce 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -272,6 +272,7 @@ struct cpsw_host_regs { }; struct cpsw_slave_data { + struct device_node *slave_node; struct device_node *phy_node; charphy_id[MII_BUS_ID_SIZE]; int phy_if; -- 2.20.1
Re: [PATCH] net: dsa: microchip: Use gpiod_set_value_cansleep()
On 6/23/19 5:09 PM, Andrew Lunn wrote: > On Sun, Jun 23, 2019 at 02:10:36PM +0200, Marek Vasut wrote: >> Replace gpiod_set_value() with gpiod_set_value_cansleep(), as the switch >> reset GPIO can be connected to e.g. I2C GPIO expander and it is perfectly >> fine for the kernel to sleep for a bit in ksz_switch_register(). >> >> Signed-off-by: Marek Vasut > > Reviewed-by: Andrew Lunn Actually, no, I missed a change in .remove , so I'll send a V2 with this RB if you don't mind. -- Best regards, Marek Vasut
[PATCH V2] net: dsa: microchip: Use gpiod_set_value_cansleep()
Replace gpiod_set_value() with gpiod_set_value_cansleep(), as the switch reset GPIO can be connected to e.g. I2C GPIO expander and it is perfectly fine for the kernel to sleep for a bit in ksz_switch_register(). Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Linus Walleij Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: use _cansleep in .remove as well --- drivers/net/dsa/microchip/ksz_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 4f6648d5ac8b..978c59aa8efb 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -436,9 +436,9 @@ int ksz_switch_register(struct ksz_device *dev, return PTR_ERR(dev->reset_gpio); if (dev->reset_gpio) { - gpiod_set_value(dev->reset_gpio, 1); + gpiod_set_value_cansleep(dev->reset_gpio, 1); mdelay(10); - gpiod_set_value(dev->reset_gpio, 0); + gpiod_set_value_cansleep(dev->reset_gpio, 0); } mutex_init(&dev->dev_mutex); @@ -489,7 +489,7 @@ void ksz_switch_remove(struct ksz_device *dev) dsa_unregister_switch(dev->ds); if (dev->reset_gpio) - gpiod_set_value(dev->reset_gpio, 1); + gpiod_set_value_cansleep(dev->reset_gpio, 1); } EXPORT_SYMBOL(ksz_switch_remove); -- 2.20.1
[PATCH V3 06/10] net: dsa: microchip: Factor out register access opcode generation
Factor out the code which sends out the register read/write opcodes to the switch, since the code differs in single bit between read and write. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477_spi.c | 22 -- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index a34e66eccbcd..49aeb92d36fc 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -25,19 +25,24 @@ /* Enough to read all switch port registers. */ #define SPI_TX_BUF_LEN 0x100 -static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, - unsigned int len) +static u32 ksz9477_spi_cmd(u32 reg, bool read) { u32 txbuf; - int ret; txbuf = reg & SPI_ADDR_MASK; - txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT; + txbuf |= (read ? KS_SPIOP_RD : KS_SPIOP_WR) << SPI_ADDR_SHIFT; txbuf <<= SPI_TURNAROUND_SHIFT; txbuf = cpu_to_be32(txbuf); - ret = spi_write_then_read(spi, &txbuf, 4, val, len); - return ret; + return txbuf; +} + +static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf = ksz9477_spi_cmd(reg, true); + + return spi_write_then_read(spi, &txbuf, 4, val, len); } static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, @@ -45,10 +50,7 @@ static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, { u32 *txbuf = (u32 *)val; - *txbuf = reg & SPI_ADDR_MASK; - *txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT); - *txbuf <<= SPI_TURNAROUND_SHIFT; - *txbuf = cpu_to_be32(*txbuf); + *txbuf = ksz9477_spi_cmd(reg, false); return spi_write(spi, txbuf, 4 + len); } -- 2.20.1
[PATCH V3 09/10] net: dsa: microchip: Factor out regmap config generation into common header
The regmap config tables are rather similar for various generations of the KSZ8xxx/KSZ9xxx switches. Introduce a macro which allows generating those tables without duplication. Note that $regalign parameter is not used right now, but will be used in KSZ87xx series switches. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB - Increase regmap max register, to cover all switch registers - Make register swabbing configurable, to allow handling switches with only 16bit registers as well as switches with some 32bit ones --- drivers/net/dsa/microchip/ksz9477_spi.c | 29 +++--- drivers/net/dsa/microchip/ksz_common.h | 32 + 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 8c8bf3237013..5a9e27b337a8 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -14,37 +14,14 @@ #include #include "ksz_priv.h" +#include "ksz_common.h" #define SPI_ADDR_SHIFT 24 #define SPI_ADDR_ALIGN 3 #define SPI_TURNAROUND_SHIFT 5 -/* SPI frame opcodes */ -#define KS_SPIOP_RD3 -#define KS_SPIOP_WR2 - -#define KS_SPIOP_FLAG_MASK(opcode) \ - cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) - -#define KSZ_REGMAP_COMMON(width) \ - { \ - .val_bits = (width),\ - .reg_stride = (width) / 8, \ - .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ - .pad_bits = SPI_TURNAROUND_SHIFT, \ - .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ - .cache_type = REGCACHE_NONE,\ - .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ - .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ - .reg_format_endian = REGMAP_ENDIAN_BIG, \ - .val_format_endian = REGMAP_ENDIAN_BIG \ - } - -static const struct regmap_config ksz9477_regmap_config[] = { - KSZ_REGMAP_COMMON(8), - KSZ_REGMAP_COMMON(16), - KSZ_REGMAP_COMMON(32), -}; +KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT, +SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN); static int ksz9477_spi_probe(struct spi_device *spi) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c3871ed9b097..78b5ab7db403 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -133,4 +133,36 @@ static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx) return data; } +/* Regmap tables generation */ +#define KSZ_SPI_OP_RD 3 +#define KSZ_SPI_OP_WR 2 + +#define KSZ_SPI_OP_FLAG_MASK(opcode, swp, regbits, regpad) \ + cpu_to_be##swp((opcode) << ((regbits) + (regpad))) + +#define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign) \ + { \ + .val_bits = (width),\ + .reg_stride = (width) / 8, \ + .reg_bits = (regbits) + (regalign), \ + .pad_bits = (regpad), \ + .max_register = BIT(regbits) - 1, \ + .cache_type = REGCACHE_NONE,\ + .read_flag_mask = \ + KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_RD, swp,\ +regbits, regpad), \ + .write_flag_mask = \ + KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp,\ +regbits, regpad), \ + .reg_format_endian = REGMAP_ENDIAN_BIG, \ + .val_format_endian = REGMAP_ENDIAN_BIG \ + } + +#define KSZ_REGMAP_TABLE(ksz, swp, regbits, regpad, regalign) \ + static const struct regmap_config ksz##_regmap_config[] = { \ + KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \ + KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \ + KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \ + } + #endif -- 2.20.1
[PATCH V3 01/10] net: dsa: microchip: Remove ksz_{read,write}24()
These functions and callbacks are never used, remove them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477_spi.c | 25 - drivers/net/dsa/microchip/ksz_common.h | 22 -- drivers/net/dsa/microchip/ksz_priv.h| 2 -- 3 files changed, 49 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 75178624d3f5..e7118319c192 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -73,37 +73,12 @@ static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); } -static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret; - - *val = 0; - ret = ksz_spi_read(dev, reg, (u8 *)val, 3); - if (!ret) { - *val = be32_to_cpu(*val); - /* convert to 24bit */ - *val >>= 8; - } - - return ret; -} - -static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value) -{ - /* make it to big endian 24bit from MSB */ - value <<= 8; - value = cpu_to_be32(value); - return ksz_spi_write(dev, reg, &value, 3); -} - static const struct ksz_io_ops ksz9477_spi_ops = { .read8 = ksz_spi_read8, .read16 = ksz_spi_read16, - .read24 = ksz_spi_read24, .read32 = ksz_spi_read32, .write8 = ksz_spi_write8, .write16 = ksz_spi_write16, - .write24 = ksz_spi_write24, .write32 = ksz_spi_write32, .get = ksz_spi_get, .set = ksz_spi_set, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 21cd794e18f1..1781539c3a81 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -61,17 +61,6 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) return ret; } -static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->read24(dev, reg, val); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) { int ret; @@ -105,17 +94,6 @@ static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) return ret; } -static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->write24(dev, reg, value); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) { int ret; diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h index c615d2a81dd5..5ef6153bd2cc 100644 --- a/drivers/net/dsa/microchip/ksz_priv.h +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -105,11 +105,9 @@ struct ksz_device { struct ksz_io_ops { int (*read8)(struct ksz_device *dev, u32 reg, u8 *value); int (*read16)(struct ksz_device *dev, u32 reg, u16 *value); - int (*read24)(struct ksz_device *dev, u32 reg, u32 *value); int (*read32)(struct ksz_device *dev, u32 reg, u32 *value); int (*write8)(struct ksz_device *dev, u32 reg, u8 value); int (*write16)(struct ksz_device *dev, u32 reg, u16 value); - int (*write24)(struct ksz_device *dev, u32 reg, u32 value); int (*write32)(struct ksz_device *dev, u32 reg, u32 value); int (*get)(struct ksz_device *dev, u32 reg, void *data, size_t len); int (*set)(struct ksz_device *dev, u32 reg, void *data, size_t len); -- 2.20.1
[PATCH V3 08/10] net: dsa: microchip: Dispose of ksz_io_ops
Since the driver now uses regmap , get rid of ad-hoc ksz_io_ops abstraction, which no longer has any meaning. Moreover, since regmap has it's own locking, get rid of the register access mutex. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: Use separate regmaps for 8/16/32bit registers V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477_spi.c | 57 + drivers/net/dsa/microchip/ksz_common.c | 6 +-- drivers/net/dsa/microchip/ksz_common.h | 50 ++ drivers/net/dsa/microchip/ksz_priv.h| 16 +-- 4 files changed, 17 insertions(+), 112 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 77e3cb100eae..8c8bf3237013 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -46,67 +46,12 @@ static const struct regmap_config ksz9477_regmap_config[] = { KSZ_REGMAP_COMMON(32), }; -static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) -{ - unsigned int value; - int ret = regmap_read(dev->regmap, reg, &value); - - *val = value; - return ret; -} - -static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) -{ - int ret = regmap_bulk_read(dev->regmap, reg, val, 2); - - if (!ret) - *val = be16_to_cpu(*val); - - return ret; -} - -static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret = regmap_bulk_read(dev->regmap, reg, val, 4); - - if (!ret) - *val = be32_to_cpu(*val); - - return ret; -} - -static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) -{ - return regmap_write(dev->regmap, reg, value); -} - -static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) -{ - value = cpu_to_be16(value); - return regmap_bulk_write(dev->regmap, reg, &value, 2); -} - -static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) -{ - value = cpu_to_be32(value); - return regmap_bulk_write(dev->regmap, reg, &value, 4); -} - -static const struct ksz_io_ops ksz9477_spi_ops = { - .read8 = ksz_spi_read8, - .read16 = ksz_spi_read16, - .read32 = ksz_spi_read32, - .write8 = ksz_spi_write8, - .write16 = ksz_spi_write16, - .write32 = ksz_spi_write32, -}; - static int ksz9477_spi_probe(struct spi_device *spi) { struct ksz_device *dev; int i, ret; - dev = ksz_switch_alloc(&spi->dev, &ksz9477_spi_ops, spi); + dev = ksz_switch_alloc(&spi->dev, spi); if (!dev) return -ENOMEM; diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 978c59aa8efb..a3d2d67894bd 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -396,9 +396,7 @@ void ksz_disable_port(struct dsa_switch *ds, int port) } EXPORT_SYMBOL_GPL(ksz_disable_port); -struct ksz_device *ksz_switch_alloc(struct device *base, - const struct ksz_io_ops *ops, - void *priv) +struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) { struct dsa_switch *ds; struct ksz_device *swdev; @@ -416,7 +414,6 @@ struct ksz_device *ksz_switch_alloc(struct device *base, swdev->ds = ds; swdev->priv = priv; - swdev->ops = ops; return swdev; } @@ -442,7 +439,6 @@ int ksz_switch_register(struct ksz_device *dev, } mutex_init(&dev->dev_mutex); - mutex_init(&dev->reg_mutex); mutex_init(&dev->stats_mutex); mutex_init(&dev->alu_mutex); mutex_init(&dev->vlan_mutex); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index fe576a00facf..c3871ed9b097 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -7,6 +7,8 @@ #ifndef __KSZ_COMMON_H #define __KSZ_COMMON_H +#include + void ksz_port_cleanup(struct ksz_device *dev, int port); void ksz_update_port_member(struct ksz_device *dev, int port); void ksz_init_mib_timer(struct ksz_device *dev); @@ -41,68 +43,44 @@ void ksz_disable_port(struct dsa_switch *ds, int port); static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) { - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->read8(dev, reg, val); - mutex_unlock(&dev->reg_mutex); + unsigned int value; + int ret = regmap_read(dev->regmap[0], reg, &value); + *val = value; return ret; } static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) { - int ret; - - mutex_lock(&d
[PATCH V3 10/10] net: dsa: microchip: Replace ad-hoc bit manipulation with regmap
Regmap provides bit manipulation functions to set/clear bits, use those insted of reimplementing them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477.c | 46 - 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 7d209fd9f26f..8f13dcc05a10 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -67,60 +67,26 @@ static const struct { static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { - u8 data; - - ksz_read8(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write8(dev, addr, data); + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); } static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - u32 addr; - u8 data; - - addr = PORT_CTRL_ADDR(port, offset); - ksz_read8(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write8(dev, addr, data); + regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); } static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) { - u32 data; - - ksz_read32(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write32(dev, addr, data); + regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); } static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, u32 bits, bool set) { - u32 addr; - u32 data; - - addr = PORT_CTRL_ADDR(port, offset); - ksz_read32(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write32(dev, addr, data); + regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); } static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, -- 2.20.1
[PATCH V3 07/10] net: dsa: microchip: Initial SPI regmap support
Add basic SPI regmap support into the driver. Previous patches unconver that ksz_spi_write() is always ever called with len = 1, 2 or 4. We can thus drop the if (len > SPI_TX_BUF_LEN) check and we can also drop the allocation of the txbuf which is part of the driver data and wastes 256 bytes for no reason. Regmap covers the whole thing now. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: - Squash with "net: dsa: microchip: Remove dev->txbuf" - Use separate regmaps for 8/16/32bit registers - Increase the regmap size to 0xd00 to cover the entire register area V3: - Rebase on next/master - Test on KSZ9477EVB - Increase regmap max register, to cover all switch registers - Correct regmap reg_bits value to match the hardware - Use cpu_to_be32() instead of cpu_to_le16() in register masks, since the KSZ9477 has some 32bit registers. --- drivers/net/dsa/microchip/Kconfig | 1 + drivers/net/dsa/microchip/ksz9477_spi.c | 114 +++- drivers/net/dsa/microchip/ksz_priv.h| 3 +- 3 files changed, 52 insertions(+), 66 deletions(-) diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 2c3a6751bdaf..56790d544eb2 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config NET_DSA_MICROCHIP_KSZ_COMMON + select REGMAP_SPI tristate menuconfig NET_DSA_MICROCHIP_KSZ9477 diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 49aeb92d36fc..77e3cb100eae 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -10,78 +10,54 @@ #include #include #include +#include #include #include "ksz_priv.h" -/* SPI frame opcodes */ -#define KS_SPIOP_RD3 -#define KS_SPIOP_WR2 - #define SPI_ADDR_SHIFT 24 -#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1) +#define SPI_ADDR_ALIGN 3 #define SPI_TURNAROUND_SHIFT 5 -/* Enough to read all switch port registers. */ -#define SPI_TX_BUF_LEN 0x100 - -static u32 ksz9477_spi_cmd(u32 reg, bool read) -{ - u32 txbuf; - - txbuf = reg & SPI_ADDR_MASK; - txbuf |= (read ? KS_SPIOP_RD : KS_SPIOP_WR) << SPI_ADDR_SHIFT; - txbuf <<= SPI_TURNAROUND_SHIFT; - txbuf = cpu_to_be32(txbuf); - - return txbuf; -} - -static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, - unsigned int len) -{ - u32 txbuf = ksz9477_spi_cmd(reg, true); - - return spi_write_then_read(spi, &txbuf, 4, val, len); -} - -static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, -unsigned int len) -{ - u32 *txbuf = (u32 *)val; - - *txbuf = ksz9477_spi_cmd(reg, false); - - return spi_write(spi, txbuf, 4 + len); -} - -static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, - unsigned int len) -{ - struct spi_device *spi = dev->priv; - - return ksz9477_spi_read_reg(spi, reg, data, len); -} - -static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, -unsigned int len) -{ - struct spi_device *spi = dev->priv; +/* SPI frame opcodes */ +#define KS_SPIOP_RD3 +#define KS_SPIOP_WR2 - if (len > SPI_TX_BUF_LEN) - len = SPI_TX_BUF_LEN; - memcpy(&dev->txbuf[4], data, len); - return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); -} +#define KS_SPIOP_FLAG_MASK(opcode) \ + cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) + +#define KSZ_REGMAP_COMMON(width) \ + { \ + .val_bits = (width),\ + .reg_stride = (width) / 8, \ + .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ + .pad_bits = SPI_TURNAROUND_SHIFT, \ + .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ + .cache_type = REGCACHE_NONE,\ + .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ + .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ + .reg_format_endian = REGMAP_ENDIAN_BIG, \ + .val_format_endian = REGMAP_ENDIAN_BIG \ + } + +static const struct regmap_config ksz9477_regmap_config[] = { + KSZ_REGMAP_COMMON(8), + KSZ_REGMAP_COMMON(16), + KSZ_REGMAP_COMMON(32), +
[PATCH V3 04/10] net: dsa: microchip: Move ksz_cfg and ksz_port_cfg to ksz9477.c
These functions are only used by the KSZ9477 code, move them from the header into that code. Note that these functions will be soon replaced by regmap equivalents. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477.c| 29 ++ drivers/net/dsa/microchip/ksz_common.h | 29 -- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 508380f80875..e8b96566abd9 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -65,6 +65,35 @@ static const struct { { 0x83, "tx_discards" }, }; +static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + u8 data; + + ksz_read8(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write8(dev, addr, data); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, +bool set) +{ + u32 addr; + u8 data; + + addr = dev->dev_ops->get_port_addr(port, offset); + ksz_read8(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write8(dev, addr, data); +} + static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) { u32 data; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c15b49528bad..fe576a00facf 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -141,35 +141,6 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) -{ - u8 data; - - ksz_read8(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write8(dev, addr, data); -} - -static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, -bool set) -{ - u32 addr; - u8 data; - - addr = dev->dev_ops->get_port_addr(port, offset); - ksz_read8(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write8(dev, addr, data); -} - struct ksz_poll_ctx { struct ksz_device *dev; int port; -- 2.20.1
[PATCH V3 00/10] net: dsa: microchip: Convert to regmap
This patchset converts KSZ9477 switch driver to regmap. This was tested with extra patches on KSZ8795. This was also tested on KSZ9477 on Microchip KSZ9477EVB board, which I now have. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Marek Vasut (10): net: dsa: microchip: Remove ksz_{read,write}24() net: dsa: microchip: Remove ksz_{get,set}() net: dsa: microchip: Inline ksz_spi.h net: dsa: microchip: Move ksz_cfg and ksz_port_cfg to ksz9477.c net: dsa: microchip: Use PORT_CTRL_ADDR() instead of indirect function call net: dsa: microchip: Factor out register access opcode generation net: dsa: microchip: Initial SPI regmap support net: dsa: microchip: Dispose of ksz_io_ops net: dsa: microchip: Factor out regmap config generation into common header net: dsa: microchip: Replace ad-hoc bit manipulation with regmap drivers/net/dsa/microchip/Kconfig | 1 + drivers/net/dsa/microchip/ksz9477.c | 35 +++--- drivers/net/dsa/microchip/ksz9477_spi.c | 114 +++-- drivers/net/dsa/microchip/ksz_common.c | 6 +- drivers/net/dsa/microchip/ksz_common.h | 157 +++- drivers/net/dsa/microchip/ksz_priv.h| 23 +--- drivers/net/dsa/microchip/ksz_spi.h | 69 --- 7 files changed, 84 insertions(+), 321 deletions(-) delete mode 100644 drivers/net/dsa/microchip/ksz_spi.h -- 2.20.1
[PATCH V3 03/10] net: dsa: microchip: Inline ksz_spi.h
The functions in the header file are static, and the header file is included from single C file, just inline the code into the C file. The bonus is that it's easier to spot further content to clean up. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477_spi.c | 43 +- drivers/net/dsa/microchip/ksz_spi.h | 59 - 2 files changed, 42 insertions(+), 60 deletions(-) delete mode 100644 drivers/net/dsa/microchip/ksz_spi.h diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 86d12d48a2a9..a34e66eccbcd 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -13,7 +13,6 @@ #include #include "ksz_priv.h" -#include "ksz_spi.h" /* SPI frame opcodes */ #define KS_SPIOP_RD3 @@ -73,6 +72,48 @@ static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); } +static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + return ksz_spi_read(dev, reg, val, 1); +} + +static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); + + if (!ret) + *val = be16_to_cpu(*val); + + return ret; +} + +static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); + + if (!ret) + *val = be32_to_cpu(*val); + + return ret; +} + +static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + return ksz_spi_write(dev, reg, &value, 1); +} + +static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + value = cpu_to_be16(value); + return ksz_spi_write(dev, reg, &value, 2); +} + +static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + value = cpu_to_be32(value); + return ksz_spi_write(dev, reg, &value, 4); +} + static const struct ksz_io_ops ksz9477_spi_ops = { .read8 = ksz_spi_read8, .read16 = ksz_spi_read16, diff --git a/drivers/net/dsa/microchip/ksz_spi.h b/drivers/net/dsa/microchip/ksz_spi.h deleted file mode 100644 index 976bace31f37.. --- a/drivers/net/dsa/microchip/ksz_spi.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Microchip KSZ series SPI access common header - * - * Copyright (C) 2017-2018 Microchip Technology Inc. - * Tristram Ha - */ - -#ifndef __KSZ_SPI_H -#define __KSZ_SPI_H - -/* Chip dependent SPI access */ -static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, - unsigned int len); -static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, -unsigned int len); - -static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) -{ - return ksz_spi_read(dev, reg, val, 1); -} - -static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) -{ - int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); - - if (!ret) - *val = be16_to_cpu(*val); - - return ret; -} - -static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); - - if (!ret) - *val = be32_to_cpu(*val); - - return ret; -} - -static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) -{ - return ksz_spi_write(dev, reg, &value, 1); -} - -static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) -{ - value = cpu_to_be16(value); - return ksz_spi_write(dev, reg, &value, 2); -} - -static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) -{ - value = cpu_to_be32(value); - return ksz_spi_write(dev, reg, &value, 4); -} - -#endif -- 2.20.1
[PATCH V3 02/10] net: dsa: microchip: Remove ksz_{get,set}()
These functions and callbacks are never used, remove them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477_spi.c | 2 -- drivers/net/dsa/microchip/ksz_common.h | 24 drivers/net/dsa/microchip/ksz_priv.h| 2 -- drivers/net/dsa/microchip/ksz_spi.h | 10 -- 4 files changed, 38 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index e7118319c192..86d12d48a2a9 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -80,8 +80,6 @@ static const struct ksz_io_ops ksz9477_spi_ops = { .write8 = ksz_spi_write8, .write16 = ksz_spi_write16, .write32 = ksz_spi_write32, - .get = ksz_spi_get, - .set = ksz_spi_set, }; static int ksz9477_spi_probe(struct spi_device *spi) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 1781539c3a81..c15b49528bad 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -105,30 +105,6 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) return ret; } -static inline int ksz_get(struct ksz_device *dev, u32 reg, void *data, - size_t len) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->get(dev, reg, data, len); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - -static inline int ksz_set(struct ksz_device *dev, u32 reg, void *data, - size_t len) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->set(dev, reg, data, len); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline void ksz_pread8(struct ksz_device *dev, int port, int offset, u8 *data) { diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h index 5ef6153bd2cc..d3ddf98156bb 100644 --- a/drivers/net/dsa/microchip/ksz_priv.h +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -109,8 +109,6 @@ struct ksz_io_ops { int (*write8)(struct ksz_device *dev, u32 reg, u8 value); int (*write16)(struct ksz_device *dev, u32 reg, u16 value); int (*write32)(struct ksz_device *dev, u32 reg, u32 value); - int (*get)(struct ksz_device *dev, u32 reg, void *data, size_t len); - int (*set)(struct ksz_device *dev, u32 reg, void *data, size_t len); }; struct alu_struct { diff --git a/drivers/net/dsa/microchip/ksz_spi.h b/drivers/net/dsa/microchip/ksz_spi.h index 427811bd60b3..976bace31f37 100644 --- a/drivers/net/dsa/microchip/ksz_spi.h +++ b/drivers/net/dsa/microchip/ksz_spi.h @@ -56,14 +56,4 @@ static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) return ksz_spi_write(dev, reg, &value, 4); } -static int ksz_spi_get(struct ksz_device *dev, u32 reg, void *data, size_t len) -{ - return ksz_spi_read(dev, reg, data, len); -} - -static int ksz_spi_set(struct ksz_device *dev, u32 reg, void *data, size_t len) -{ - return ksz_spi_write(dev, reg, data, len); -} - #endif -- 2.20.1
[PATCH V3 05/10] net: dsa: microchip: Use PORT_CTRL_ADDR() instead of indirect function call
The indirect function call to dev->dev_ops->get_port_addr() is expensive especially if called for every single register access, and only returns the value of PORT_CTRL_ADDR() macro. Use PORT_CTRL_ADDR() macro directly instead. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB --- drivers/net/dsa/microchip/ksz9477.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index e8b96566abd9..7d209fd9f26f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -83,7 +83,7 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, u32 addr; u8 data; - addr = dev->dev_ops->get_port_addr(port, offset); + addr = PORT_CTRL_ADDR(port, offset); ksz_read8(dev, addr, &data); if (set) -- 2.20.1
Re: [PATCH V3 07/10] net: dsa: microchip: Initial SPI regmap support
On 6/24/19 12:35 AM, Marek Vasut wrote: > Add basic SPI regmap support into the driver. > > Previous patches unconver that ksz_spi_write() is always ever called > with len = 1, 2 or 4. We can thus drop the if (len > SPI_TX_BUF_LEN) > check and we can also drop the allocation of the txbuf which is part > of the driver data and wastes 256 bytes for no reason. Regmap covers > the whole thing now. > > Signed-off-by: Marek Vasut > Cc: Andrew Lunn > Cc: Florian Fainelli > Cc: Tristram Ha > Cc: Woojung Huh [...] > +#define KS_SPIOP_FLAG_MASK(opcode) \ > + cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) So the robot is complaining about this. I believe this is correct, as the mask should be in native endianness on the register and NOT the native endianness of the CPU. I think a cast would help here, e.g.: - cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) - (__force unsigned long)cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) Does this make sense ? > +#define KSZ_REGMAP_COMMON(width) \ > + { \ > + .val_bits = (width),\ > + .reg_stride = (width) / 8, \ > + .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ > + .pad_bits = SPI_TURNAROUND_SHIFT, \ > + .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ > + .cache_type = REGCACHE_NONE,\ > + .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ > + .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ [...] -- Best regards, Marek Vasut
Re: [PATCH V3 05/10] net: dsa: microchip: Use PORT_CTRL_ADDR() instead of indirect function call
On 6/24/19 5:20 AM, Andrew Lunn wrote: > On Mon, Jun 24, 2019 at 12:35:03AM +0200, Marek Vasut wrote: >> The indirect function call to dev->dev_ops->get_port_addr() is expensive >> especially if called for every single register access, and only returns >> the value of PORT_CTRL_ADDR() macro. Use PORT_CTRL_ADDR() macro directly >> instead. > > Hi Marek > > Rather than change just one instance, it would be better to change > them all. And then remove dev_ops->get_port_addr(). So that actually doesn't work. The rest of the calls are in common code (ksz_common.h) and I plan to add the KSZ8795, which has different spacing between the ports, so those have to stay. Although, depending on how things look, I will do more regmap cleanups, the driver needs it. Since I have the KSZ9477 devkit, that also makes it much easier to test the changes. I think inlining those custom accessors would be high on the list, because they are just a mess. But that's for another series. -- Best regards, Marek Vasut
Re: [PATCH V3 07/10] net: dsa: microchip: Initial SPI regmap support
On 6/25/19 1:59 AM, Vladimir Oltean wrote: > On Tue, 25 Jun 2019 at 01:17, Marek Vasut wrote: >> >> On 6/24/19 12:35 AM, Marek Vasut wrote: >>> Add basic SPI regmap support into the driver. >>> >>> Previous patches unconver that ksz_spi_write() is always ever called >>> with len = 1, 2 or 4. We can thus drop the if (len > SPI_TX_BUF_LEN) >>> check and we can also drop the allocation of the txbuf which is part >>> of the driver data and wastes 256 bytes for no reason. Regmap covers >>> the whole thing now. >>> >>> Signed-off-by: Marek Vasut >>> Cc: Andrew Lunn >>> Cc: Florian Fainelli >>> Cc: Tristram Ha >>> Cc: Woojung Huh >> >> [...] >> >>> +#define KS_SPIOP_FLAG_MASK(opcode) \ >>> + cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) >> >> So the robot is complaining about this. I believe this is correct, as >> the mask should be in native endianness on the register and NOT the >> native endianness of the CPU. >> >> I think a cast would help here, e.g.: >> - cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) >> - (__force unsigned long)cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + >> SPI_TURNAROUND_SHIFT)) >> >> Does this make sense ? >> >>> +#define KSZ_REGMAP_COMMON(width) \ >>> + { \ >>> + .val_bits = (width),\ >>> + .reg_stride = (width) / 8, \ >>> + .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ >>> + .pad_bits = SPI_TURNAROUND_SHIFT, \ >>> + .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ >>> + .cache_type = REGCACHE_NONE,\ >>> + .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ >>> + .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ >> >> [...] >> >> -- >> Best regards, >> Marek Vasut > > Hi Marek, > > I saw SPI buffers and endianness and got triggered :) > Would it make sense to take a look at CONFIG_PACKING for the KSZ9477 driver? > I don't know how bad the field alignment issue is on that hardware, > but on SJA1105 it was such a disaster that I couldn't have managed it > any other way. How does that help me here ? All I really need is a static constant mask for the register/flags , 32bit for KSZ9xxx and 16bit for KSZ87xx. I don't need any dynamic stuff, luckily. But I'm glad to see TJA1105 driver mainline :) -- Best regards, Marek Vasut
Re: [PATCH V3 07/10] net: dsa: microchip: Initial SPI regmap support
On 6/25/19 2:40 PM, Vladimir Oltean wrote: > On Tue, 25 Jun 2019 at 15:06, Marek Vasut wrote: >> >> On 6/25/19 1:59 AM, Vladimir Oltean wrote: >>> On Tue, 25 Jun 2019 at 01:17, Marek Vasut wrote: >>>> >>>> On 6/24/19 12:35 AM, Marek Vasut wrote: >>>>> Add basic SPI regmap support into the driver. >>>>> >>>>> Previous patches unconver that ksz_spi_write() is always ever called >>>>> with len = 1, 2 or 4. We can thus drop the if (len > SPI_TX_BUF_LEN) >>>>> check and we can also drop the allocation of the txbuf which is part >>>>> of the driver data and wastes 256 bytes for no reason. Regmap covers >>>>> the whole thing now. >>>>> >>>>> Signed-off-by: Marek Vasut >>>>> Cc: Andrew Lunn >>>>> Cc: Florian Fainelli >>>>> Cc: Tristram Ha >>>>> Cc: Woojung Huh >>>> >>>> [...] >>>> >>>>> +#define KS_SPIOP_FLAG_MASK(opcode) \ >>>>> + cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) >>>> >>>> So the robot is complaining about this. I believe this is correct, as >>>> the mask should be in native endianness on the register and NOT the >>>> native endianness of the CPU. >>>> >>>> I think a cast would help here, e.g.: >>>> - cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) >>>> - (__force unsigned long)cpu_to_be32((opcode) << (SPI_ADDR_SHIFT + >>>> SPI_TURNAROUND_SHIFT)) >>>> >>>> Does this make sense ? >>>> >>>>> +#define KSZ_REGMAP_COMMON(width) \ >>>>> + { \ >>>>> + .val_bits = (width),\ >>>>> + .reg_stride = (width) / 8, \ >>>>> + .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ >>>>> + .pad_bits = SPI_TURNAROUND_SHIFT, \ >>>>> + .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ >>>>> + .cache_type = REGCACHE_NONE,\ >>>>> + .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ >>>>> + .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ >>>> >>>> [...] >>>> >>>> -- >>>> Best regards, >>>> Marek Vasut >>> >>> Hi Marek, >>> >>> I saw SPI buffers and endianness and got triggered :) >>> Would it make sense to take a look at CONFIG_PACKING for the KSZ9477 driver? >>> I don't know how bad the field alignment issue is on that hardware, >>> but on SJA1105 it was such a disaster that I couldn't have managed it >>> any other way. >> >> How does that help me here ? All I really need is a static constant mask >> for the register/flags , 32bit for KSZ9xxx and 16bit for KSZ87xx. I >> don't need any dynamic stuff, luckily. >> > > Ok. I was thinking *instead of* regmap. > On the SJA1105 I couldn't use a spi regmap because: > * the enum regmap_endian wasn't enough to describe the hardware's bit > layout (it is big endian, but high-order and low-order 32 bit words > are swapped) Oof. Is the switch development some competition in register layout braindeath ? What's it gonna be next ... I was gonna suggest something, but then reconsidered, better not give them any wild ideas :-) > * it doesn't really expose a well-defined register map, but rather, > you're supposed to dynamically construct a TLV-type buffer and write > it starting with a fixed address. > I just thought you were facing some of these problems as well with > regmap. If not, that's perfectly fine! All right, that's not the case here, whew. -- Best regards, Marek Vasut
[PATCH V4 09/10] net: dsa: microchip: Factor out regmap config generation into common header
The regmap config tables are rather similar for various generations of the KSZ8xxx/KSZ9xxx switches. Introduce a macro which allows generating those tables without duplication. Note that $regalign parameter is not used right now, but will be used in KSZ87xx series switches. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB - Increase regmap max register, to cover all switch registers - Make register swabbing configurable, to allow handling switches with only 16bit registers as well as switches with some 32bit ones V4: No change --- drivers/net/dsa/microchip/ksz9477_spi.c | 29 +++--- drivers/net/dsa/microchip/ksz_common.h | 32 + 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index d1ffdf51d58c..5a9e27b337a8 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -14,37 +14,14 @@ #include #include "ksz_priv.h" +#include "ksz_common.h" #define SPI_ADDR_SHIFT 24 #define SPI_ADDR_ALIGN 3 #define SPI_TURNAROUND_SHIFT 5 -/* SPI frame opcodes */ -#define KS_SPIOP_RD3 -#define KS_SPIOP_WR2 - -#define KS_SPIOP_FLAG_MASK(opcode) \ - swab32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) - -#define KSZ_REGMAP_COMMON(width) \ - { \ - .val_bits = (width),\ - .reg_stride = (width) / 8, \ - .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ - .pad_bits = SPI_TURNAROUND_SHIFT, \ - .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ - .cache_type = REGCACHE_NONE,\ - .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ - .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR), \ - .reg_format_endian = REGMAP_ENDIAN_BIG, \ - .val_format_endian = REGMAP_ENDIAN_BIG \ - } - -static const struct regmap_config ksz9477_regmap_config[] = { - KSZ_REGMAP_COMMON(8), - KSZ_REGMAP_COMMON(16), - KSZ_REGMAP_COMMON(32), -}; +KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT, +SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN); static int ksz9477_spi_probe(struct spi_device *spi) { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c3871ed9b097..745318424f71 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -133,4 +133,36 @@ static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx) return data; } +/* Regmap tables generation */ +#define KSZ_SPI_OP_RD 3 +#define KSZ_SPI_OP_WR 2 + +#define KSZ_SPI_OP_FLAG_MASK(opcode, swp, regbits, regpad) \ + swab##swp((opcode) << ((regbits) + (regpad))) + +#define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign) \ + { \ + .val_bits = (width),\ + .reg_stride = (width) / 8, \ + .reg_bits = (regbits) + (regalign), \ + .pad_bits = (regpad), \ + .max_register = BIT(regbits) - 1, \ + .cache_type = REGCACHE_NONE,\ + .read_flag_mask = \ + KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_RD, swp,\ +regbits, regpad), \ + .write_flag_mask = \ + KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp,\ +regbits, regpad), \ + .reg_format_endian = REGMAP_ENDIAN_BIG, \ + .val_format_endian = REGMAP_ENDIAN_BIG \ + } + +#define KSZ_REGMAP_TABLE(ksz, swp, regbits, regpad, regalign) \ + static const struct regmap_config ksz##_regmap_config[] = { \ + KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \ + KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \ + KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \ + } + #endif -- 2.20.1
[PATCH V4 10/10] net: dsa: microchip: Replace ad-hoc bit manipulation with regmap
Regmap provides bit manipulation functions to set/clear bits, use those insted of reimplementing them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB V4: No change --- drivers/net/dsa/microchip/ksz9477.c | 46 - 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 7d209fd9f26f..8f13dcc05a10 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -67,60 +67,26 @@ static const struct { static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { - u8 data; - - ksz_read8(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write8(dev, addr, data); + regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); } static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - u32 addr; - u8 data; - - addr = PORT_CTRL_ADDR(port, offset); - ksz_read8(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write8(dev, addr, data); + regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); } static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) { - u32 data; - - ksz_read32(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write32(dev, addr, data); + regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); } static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, u32 bits, bool set) { - u32 addr; - u32 data; - - addr = PORT_CTRL_ADDR(port, offset); - ksz_read32(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write32(dev, addr, data); + regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), + bits, set ? bits : 0); } static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, -- 2.20.1
[PATCH V4 06/10] net: dsa: microchip: Factor out register access opcode generation
Factor out the code which sends out the register read/write opcodes to the switch, since the code differs in single bit between read and write. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB V4: Add RB --- drivers/net/dsa/microchip/ksz9477_spi.c | 22 -- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index a34e66eccbcd..49aeb92d36fc 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -25,19 +25,24 @@ /* Enough to read all switch port registers. */ #define SPI_TX_BUF_LEN 0x100 -static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, - unsigned int len) +static u32 ksz9477_spi_cmd(u32 reg, bool read) { u32 txbuf; - int ret; txbuf = reg & SPI_ADDR_MASK; - txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT; + txbuf |= (read ? KS_SPIOP_RD : KS_SPIOP_WR) << SPI_ADDR_SHIFT; txbuf <<= SPI_TURNAROUND_SHIFT; txbuf = cpu_to_be32(txbuf); - ret = spi_write_then_read(spi, &txbuf, 4, val, len); - return ret; + return txbuf; +} + +static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf = ksz9477_spi_cmd(reg, true); + + return spi_write_then_read(spi, &txbuf, 4, val, len); } static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, @@ -45,10 +50,7 @@ static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, { u32 *txbuf = (u32 *)val; - *txbuf = reg & SPI_ADDR_MASK; - *txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT); - *txbuf <<= SPI_TURNAROUND_SHIFT; - *txbuf = cpu_to_be32(*txbuf); + *txbuf = ksz9477_spi_cmd(reg, false); return spi_write(spi, txbuf, 4 + len); } -- 2.20.1
[PATCH V4 08/10] net: dsa: microchip: Dispose of ksz_io_ops
Since the driver now uses regmap , get rid of ad-hoc ksz_io_ops abstraction, which no longer has any meaning. Moreover, since regmap has it's own locking, get rid of the register access mutex. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: Use separate regmaps for 8/16/32bit registers V3: - Rebase on next/master - Test on KSZ9477EVB V4: No change --- drivers/net/dsa/microchip/ksz9477_spi.c | 57 + drivers/net/dsa/microchip/ksz_common.c | 6 +-- drivers/net/dsa/microchip/ksz_common.h | 50 ++ drivers/net/dsa/microchip/ksz_priv.h| 16 +-- 4 files changed, 17 insertions(+), 112 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index c72645354dc2..d1ffdf51d58c 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -46,67 +46,12 @@ static const struct regmap_config ksz9477_regmap_config[] = { KSZ_REGMAP_COMMON(32), }; -static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) -{ - unsigned int value; - int ret = regmap_read(dev->regmap, reg, &value); - - *val = value; - return ret; -} - -static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) -{ - int ret = regmap_bulk_read(dev->regmap, reg, val, 2); - - if (!ret) - *val = be16_to_cpu(*val); - - return ret; -} - -static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret = regmap_bulk_read(dev->regmap, reg, val, 4); - - if (!ret) - *val = be32_to_cpu(*val); - - return ret; -} - -static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) -{ - return regmap_write(dev->regmap, reg, value); -} - -static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) -{ - value = cpu_to_be16(value); - return regmap_bulk_write(dev->regmap, reg, &value, 2); -} - -static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) -{ - value = cpu_to_be32(value); - return regmap_bulk_write(dev->regmap, reg, &value, 4); -} - -static const struct ksz_io_ops ksz9477_spi_ops = { - .read8 = ksz_spi_read8, - .read16 = ksz_spi_read16, - .read32 = ksz_spi_read32, - .write8 = ksz_spi_write8, - .write16 = ksz_spi_write16, - .write32 = ksz_spi_write32, -}; - static int ksz9477_spi_probe(struct spi_device *spi) { struct ksz_device *dev; int i, ret; - dev = ksz_switch_alloc(&spi->dev, &ksz9477_spi_ops, spi); + dev = ksz_switch_alloc(&spi->dev, spi); if (!dev) return -ENOMEM; diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 978c59aa8efb..a3d2d67894bd 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -396,9 +396,7 @@ void ksz_disable_port(struct dsa_switch *ds, int port) } EXPORT_SYMBOL_GPL(ksz_disable_port); -struct ksz_device *ksz_switch_alloc(struct device *base, - const struct ksz_io_ops *ops, - void *priv) +struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) { struct dsa_switch *ds; struct ksz_device *swdev; @@ -416,7 +414,6 @@ struct ksz_device *ksz_switch_alloc(struct device *base, swdev->ds = ds; swdev->priv = priv; - swdev->ops = ops; return swdev; } @@ -442,7 +439,6 @@ int ksz_switch_register(struct ksz_device *dev, } mutex_init(&dev->dev_mutex); - mutex_init(&dev->reg_mutex); mutex_init(&dev->stats_mutex); mutex_init(&dev->alu_mutex); mutex_init(&dev->vlan_mutex); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index fe576a00facf..c3871ed9b097 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -7,6 +7,8 @@ #ifndef __KSZ_COMMON_H #define __KSZ_COMMON_H +#include + void ksz_port_cleanup(struct ksz_device *dev, int port); void ksz_update_port_member(struct ksz_device *dev, int port); void ksz_init_mib_timer(struct ksz_device *dev); @@ -41,68 +43,44 @@ void ksz_disable_port(struct dsa_switch *ds, int port); static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) { - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->read8(dev, reg, val); - mutex_unlock(&dev->reg_mutex); + unsigned int value; + int ret = regmap_read(dev->regmap[0], reg, &value); + *val = value; return ret; } static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) { - int ret; - - mutex_lock(
[PATCH V4 04/10] net: dsa: microchip: Move ksz_cfg and ksz_port_cfg to ksz9477.c
These functions are only used by the KSZ9477 code, move them from the header into that code. Note that these functions will be soon replaced by regmap equivalents. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB V4: Add RB --- drivers/net/dsa/microchip/ksz9477.c| 29 ++ drivers/net/dsa/microchip/ksz_common.h | 29 -- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 508380f80875..e8b96566abd9 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -65,6 +65,35 @@ static const struct { { 0x83, "tx_discards" }, }; +static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + u8 data; + + ksz_read8(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write8(dev, addr, data); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, +bool set) +{ + u32 addr; + u8 data; + + addr = dev->dev_ops->get_port_addr(port, offset); + ksz_read8(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write8(dev, addr, data); +} + static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) { u32 data; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c15b49528bad..fe576a00facf 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -141,35 +141,6 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) -{ - u8 data; - - ksz_read8(dev, addr, &data); - if (set) - data |= bits; - else - data &= ~bits; - ksz_write8(dev, addr, data); -} - -static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, -bool set) -{ - u32 addr; - u8 data; - - addr = dev->dev_ops->get_port_addr(port, offset); - ksz_read8(dev, addr, &data); - - if (set) - data |= bits; - else - data &= ~bits; - - ksz_write8(dev, addr, data); -} - struct ksz_poll_ctx { struct ksz_device *dev; int port; -- 2.20.1
[PATCH V4 00/10] net: dsa: microchip: Convert to regmap
This patchset converts KSZ9477 switch driver to regmap. This was tested with extra patches on KSZ8795. This was also tested on KSZ9477 on Microchip KSZ9477EVB board, which I now have. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Marek Vasut (10): net: dsa: microchip: Remove ksz_{read,write}24() net: dsa: microchip: Remove ksz_{get,set}() net: dsa: microchip: Inline ksz_spi.h net: dsa: microchip: Move ksz_cfg and ksz_port_cfg to ksz9477.c net: dsa: microchip: Use PORT_CTRL_ADDR() instead of indirect function call net: dsa: microchip: Factor out register access opcode generation net: dsa: microchip: Initial SPI regmap support net: dsa: microchip: Dispose of ksz_io_ops net: dsa: microchip: Factor out regmap config generation into common header net: dsa: microchip: Replace ad-hoc bit manipulation with regmap drivers/net/dsa/microchip/Kconfig | 1 + drivers/net/dsa/microchip/ksz9477.c | 35 +++--- drivers/net/dsa/microchip/ksz9477_spi.c | 114 +++-- drivers/net/dsa/microchip/ksz_common.c | 6 +- drivers/net/dsa/microchip/ksz_common.h | 157 +++- drivers/net/dsa/microchip/ksz_priv.h| 23 +--- drivers/net/dsa/microchip/ksz_spi.h | 69 --- 7 files changed, 84 insertions(+), 321 deletions(-) delete mode 100644 drivers/net/dsa/microchip/ksz_spi.h -- 2.20.1
[PATCH V4 07/10] net: dsa: microchip: Initial SPI regmap support
Add basic SPI regmap support into the driver. Previous patches unconver that ksz_spi_write() is always ever called with len = 1, 2 or 4. We can thus drop the if (len > SPI_TX_BUF_LEN) check and we can also drop the allocation of the txbuf which is part of the driver data and wastes 256 bytes for no reason. Regmap covers the whole thing now. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: - Squash with "net: dsa: microchip: Remove dev->txbuf" - Use separate regmaps for 8/16/32bit registers - Increase the regmap size to 0xd00 to cover the entire register area V3: - Rebase on next/master - Test on KSZ9477EVB - Increase regmap max register, to cover all switch registers - Correct regmap reg_bits value to match the hardware - Use cpu_to_be32() instead of cpu_to_le16() in register masks, since the KSZ9477 has some 32bit registers. V4: - Replace cpu_to_be32() with swab32() in regmap read/write_flag_masks. - Move REGMAP_SPI to NET_DSA_MICROCHIP_KSZ9477_SPI in Kconfig --- drivers/net/dsa/microchip/Kconfig | 1 + drivers/net/dsa/microchip/ksz9477_spi.c | 114 +++- drivers/net/dsa/microchip/ksz_priv.h| 3 +- 3 files changed, 52 insertions(+), 66 deletions(-) diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig index 2c3a6751bdaf..fe0a13b79c4b 100644 --- a/drivers/net/dsa/microchip/Kconfig +++ b/drivers/net/dsa/microchip/Kconfig @@ -13,5 +13,6 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477 config NET_DSA_MICROCHIP_KSZ9477_SPI tristate "KSZ9477 series SPI connected switch driver" depends on NET_DSA_MICROCHIP_KSZ9477 && SPI + select REGMAP_SPI help Select to enable support for registering switches configured through SPI. diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 49aeb92d36fc..c72645354dc2 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -10,78 +10,54 @@ #include #include #include +#include #include #include "ksz_priv.h" -/* SPI frame opcodes */ -#define KS_SPIOP_RD3 -#define KS_SPIOP_WR2 - #define SPI_ADDR_SHIFT 24 -#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1) +#define SPI_ADDR_ALIGN 3 #define SPI_TURNAROUND_SHIFT 5 -/* Enough to read all switch port registers. */ -#define SPI_TX_BUF_LEN 0x100 - -static u32 ksz9477_spi_cmd(u32 reg, bool read) -{ - u32 txbuf; - - txbuf = reg & SPI_ADDR_MASK; - txbuf |= (read ? KS_SPIOP_RD : KS_SPIOP_WR) << SPI_ADDR_SHIFT; - txbuf <<= SPI_TURNAROUND_SHIFT; - txbuf = cpu_to_be32(txbuf); - - return txbuf; -} - -static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, - unsigned int len) -{ - u32 txbuf = ksz9477_spi_cmd(reg, true); - - return spi_write_then_read(spi, &txbuf, 4, val, len); -} - -static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, -unsigned int len) -{ - u32 *txbuf = (u32 *)val; - - *txbuf = ksz9477_spi_cmd(reg, false); - - return spi_write(spi, txbuf, 4 + len); -} - -static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, - unsigned int len) -{ - struct spi_device *spi = dev->priv; - - return ksz9477_spi_read_reg(spi, reg, data, len); -} - -static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, -unsigned int len) -{ - struct spi_device *spi = dev->priv; +/* SPI frame opcodes */ +#define KS_SPIOP_RD3 +#define KS_SPIOP_WR2 - if (len > SPI_TX_BUF_LEN) - len = SPI_TX_BUF_LEN; - memcpy(&dev->txbuf[4], data, len); - return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); -} +#define KS_SPIOP_FLAG_MASK(opcode) \ + swab32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT)) + +#define KSZ_REGMAP_COMMON(width) \ + { \ + .val_bits = (width),\ + .reg_stride = (width) / 8, \ + .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,\ + .pad_bits = SPI_TURNAROUND_SHIFT, \ + .max_register = BIT(SPI_ADDR_SHIFT) - 1,\ + .cache_type = REGCACHE_NONE,\ + .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD), \ + .write_flag_mask = KS_S
[PATCH V4 01/10] net: dsa: microchip: Remove ksz_{read,write}24()
These functions and callbacks are never used, remove them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB V4: Add RB --- drivers/net/dsa/microchip/ksz9477_spi.c | 25 - drivers/net/dsa/microchip/ksz_common.h | 22 -- drivers/net/dsa/microchip/ksz_priv.h| 2 -- 3 files changed, 49 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 75178624d3f5..e7118319c192 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -73,37 +73,12 @@ static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); } -static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret; - - *val = 0; - ret = ksz_spi_read(dev, reg, (u8 *)val, 3); - if (!ret) { - *val = be32_to_cpu(*val); - /* convert to 24bit */ - *val >>= 8; - } - - return ret; -} - -static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value) -{ - /* make it to big endian 24bit from MSB */ - value <<= 8; - value = cpu_to_be32(value); - return ksz_spi_write(dev, reg, &value, 3); -} - static const struct ksz_io_ops ksz9477_spi_ops = { .read8 = ksz_spi_read8, .read16 = ksz_spi_read16, - .read24 = ksz_spi_read24, .read32 = ksz_spi_read32, .write8 = ksz_spi_write8, .write16 = ksz_spi_write16, - .write24 = ksz_spi_write24, .write32 = ksz_spi_write32, .get = ksz_spi_get, .set = ksz_spi_set, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 21cd794e18f1..1781539c3a81 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -61,17 +61,6 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) return ret; } -static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->read24(dev, reg, val); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) { int ret; @@ -105,17 +94,6 @@ static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) return ret; } -static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->write24(dev, reg, value); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) { int ret; diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h index c615d2a81dd5..5ef6153bd2cc 100644 --- a/drivers/net/dsa/microchip/ksz_priv.h +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -105,11 +105,9 @@ struct ksz_device { struct ksz_io_ops { int (*read8)(struct ksz_device *dev, u32 reg, u8 *value); int (*read16)(struct ksz_device *dev, u32 reg, u16 *value); - int (*read24)(struct ksz_device *dev, u32 reg, u32 *value); int (*read32)(struct ksz_device *dev, u32 reg, u32 *value); int (*write8)(struct ksz_device *dev, u32 reg, u8 value); int (*write16)(struct ksz_device *dev, u32 reg, u16 value); - int (*write24)(struct ksz_device *dev, u32 reg, u32 value); int (*write32)(struct ksz_device *dev, u32 reg, u32 value); int (*get)(struct ksz_device *dev, u32 reg, void *data, size_t len); int (*set)(struct ksz_device *dev, u32 reg, void *data, size_t len); -- 2.20.1
[PATCH V4 05/10] net: dsa: microchip: Use PORT_CTRL_ADDR() instead of indirect function call
The indirect function call to dev->dev_ops->get_port_addr() is expensive especially if called for every single register access, and only returns the value of PORT_CTRL_ADDR() macro. Use PORT_CTRL_ADDR() macro directly instead. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- V2: New patch V3: - Rebase on next/master - Test on KSZ9477EVB V4: No change --- drivers/net/dsa/microchip/ksz9477.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index e8b96566abd9..7d209fd9f26f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -83,7 +83,7 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, u32 addr; u8 data; - addr = dev->dev_ops->get_port_addr(port, offset); + addr = PORT_CTRL_ADDR(port, offset); ksz_read8(dev, addr, &data); if (set) -- 2.20.1
[PATCH V4 03/10] net: dsa: microchip: Inline ksz_spi.h
The functions in the header file are static, and the header file is included from single C file, just inline the code into the C file. The bonus is that it's easier to spot further content to clean up. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB V4: Add RB --- drivers/net/dsa/microchip/ksz9477_spi.c | 43 +- drivers/net/dsa/microchip/ksz_spi.h | 59 - 2 files changed, 42 insertions(+), 60 deletions(-) delete mode 100644 drivers/net/dsa/microchip/ksz_spi.h diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 86d12d48a2a9..a34e66eccbcd 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -13,7 +13,6 @@ #include #include "ksz_priv.h" -#include "ksz_spi.h" /* SPI frame opcodes */ #define KS_SPIOP_RD3 @@ -73,6 +72,48 @@ static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len); } +static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + return ksz_spi_read(dev, reg, val, 1); +} + +static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); + + if (!ret) + *val = be16_to_cpu(*val); + + return ret; +} + +static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); + + if (!ret) + *val = be32_to_cpu(*val); + + return ret; +} + +static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + return ksz_spi_write(dev, reg, &value, 1); +} + +static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + value = cpu_to_be16(value); + return ksz_spi_write(dev, reg, &value, 2); +} + +static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + value = cpu_to_be32(value); + return ksz_spi_write(dev, reg, &value, 4); +} + static const struct ksz_io_ops ksz9477_spi_ops = { .read8 = ksz_spi_read8, .read16 = ksz_spi_read16, diff --git a/drivers/net/dsa/microchip/ksz_spi.h b/drivers/net/dsa/microchip/ksz_spi.h deleted file mode 100644 index 976bace31f37.. --- a/drivers/net/dsa/microchip/ksz_spi.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * Microchip KSZ series SPI access common header - * - * Copyright (C) 2017-2018 Microchip Technology Inc. - * Tristram Ha - */ - -#ifndef __KSZ_SPI_H -#define __KSZ_SPI_H - -/* Chip dependent SPI access */ -static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, - unsigned int len); -static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data, -unsigned int len); - -static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) -{ - return ksz_spi_read(dev, reg, val, 1); -} - -static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) -{ - int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); - - if (!ret) - *val = be16_to_cpu(*val); - - return ret; -} - -static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) -{ - int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); - - if (!ret) - *val = be32_to_cpu(*val); - - return ret; -} - -static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) -{ - return ksz_spi_write(dev, reg, &value, 1); -} - -static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) -{ - value = cpu_to_be16(value); - return ksz_spi_write(dev, reg, &value, 2); -} - -static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) -{ - value = cpu_to_be32(value); - return ksz_spi_write(dev, reg, &value, 4); -} - -#endif -- 2.20.1
[PATCH V4 02/10] net: dsa: microchip: Remove ksz_{get,set}()
These functions and callbacks are never used, remove them. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Reviewed-by: Andrew Lunn --- V2: No change V3: - Rebase on next/master - Test on KSZ9477EVB V4: Add RB --- drivers/net/dsa/microchip/ksz9477_spi.c | 2 -- drivers/net/dsa/microchip/ksz_common.h | 24 drivers/net/dsa/microchip/ksz_priv.h| 2 -- drivers/net/dsa/microchip/ksz_spi.h | 10 -- 4 files changed, 38 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index e7118319c192..86d12d48a2a9 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -80,8 +80,6 @@ static const struct ksz_io_ops ksz9477_spi_ops = { .write8 = ksz_spi_write8, .write16 = ksz_spi_write16, .write32 = ksz_spi_write32, - .get = ksz_spi_get, - .set = ksz_spi_set, }; static int ksz9477_spi_probe(struct spi_device *spi) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 1781539c3a81..c15b49528bad 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -105,30 +105,6 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) return ret; } -static inline int ksz_get(struct ksz_device *dev, u32 reg, void *data, - size_t len) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->get(dev, reg, data, len); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - -static inline int ksz_set(struct ksz_device *dev, u32 reg, void *data, - size_t len) -{ - int ret; - - mutex_lock(&dev->reg_mutex); - ret = dev->ops->set(dev, reg, data, len); - mutex_unlock(&dev->reg_mutex); - - return ret; -} - static inline void ksz_pread8(struct ksz_device *dev, int port, int offset, u8 *data) { diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h index 5ef6153bd2cc..d3ddf98156bb 100644 --- a/drivers/net/dsa/microchip/ksz_priv.h +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -109,8 +109,6 @@ struct ksz_io_ops { int (*write8)(struct ksz_device *dev, u32 reg, u8 value); int (*write16)(struct ksz_device *dev, u32 reg, u16 value); int (*write32)(struct ksz_device *dev, u32 reg, u32 value); - int (*get)(struct ksz_device *dev, u32 reg, void *data, size_t len); - int (*set)(struct ksz_device *dev, u32 reg, void *data, size_t len); }; struct alu_struct { diff --git a/drivers/net/dsa/microchip/ksz_spi.h b/drivers/net/dsa/microchip/ksz_spi.h index 427811bd60b3..976bace31f37 100644 --- a/drivers/net/dsa/microchip/ksz_spi.h +++ b/drivers/net/dsa/microchip/ksz_spi.h @@ -56,14 +56,4 @@ static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) return ksz_spi_write(dev, reg, &value, 4); } -static int ksz_spi_get(struct ksz_device *dev, u32 reg, void *data, size_t len) -{ - return ksz_spi_read(dev, reg, data, len); -} - -static int ksz_spi_set(struct ksz_device *dev, u32 reg, void *data, size_t len) -{ - return ksz_spi_write(dev, reg, data, len); -} - #endif -- 2.20.1
[PATCH 1/5] net: dsa: microchip: Replace ad-hoc polling with regmap
Regmap provides polling function to poll for bits in a register, use in instead of reimplementing it. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz9477.c| 14 +- drivers/net/dsa/microchip/ksz_common.h | 14 -- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 8f13dcc05a10..ece25f38e02a 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -263,12 +263,8 @@ static int ksz9477_reset_switch(struct ksz_device *dev) static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) { - struct ksz_poll_ctx ctx = { - .dev = dev, - .port = port, - .offset = REG_PORT_MIB_CTRL_STAT__4, - }; struct ksz_port *p = &dev->ports[port]; + unsigned int val; u32 data; int ret; @@ -278,11 +274,11 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, data |= (addr << MIB_COUNTER_INDEX_S); ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); - ret = readx_poll_timeout(ksz_pread32_poll, &ctx, data, -!(data & MIB_COUNTER_READ), 10, 1000); - + ret = regmap_read_poll_timeout(dev->regmap[2], + PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4), + val, !(val & MIB_COUNTER_READ), 10, 1000); /* failed to read MIB. get out of loop */ - if (ret < 0) { + if (ret) { dev_dbg(dev->dev, "Failed to get MIB\n"); return; } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 745318424f71..ee7096d8af07 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -119,20 +119,6 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); } -struct ksz_poll_ctx { - struct ksz_device *dev; - int port; - int offset; -}; - -static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx) -{ - u32 data; - - ksz_pread32(ctx->dev, ctx->port, ctx->offset, &data); - return data; -} - /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 -- 2.20.1
[PATCH 2/5] net: dsa: microchip: Replace ksz9477_wait_vlan_ctrl_ready polling with regmap
Regmap provides polling function to poll for bits in a register. This function is another reimplementation of polling for bit being clear in a register. Replace this with regmap polling function. Moreover, inline the function parameters, as the function is never called with any other parameter values than this one. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz9477.c | 26 -- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index ece25f38e02a..0aab00bf23b9 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -89,22 +89,12 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, bits, set ? bits : 0); } -static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, - int timeout) +static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) { - u8 data; - - do { - ksz_read8(dev, REG_SW_VLAN_CTRL, &data); - if (!(data & waiton)) - break; - usleep_range(1, 10); - } while (timeout-- > 0); - - if (timeout <= 0) - return -ETIMEDOUT; + unsigned int val; - return 0; + return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, + val, !(val & VLAN_START), 10, 1000); } static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid, @@ -118,8 +108,8 @@ static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid, ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); /* wait to be cleared */ - ret = ksz9477_wait_vlan_ctrl_ready(dev, VLAN_START, 1000); - if (ret < 0) { + ret = ksz9477_wait_vlan_ctrl_ready(dev); + if (ret) { dev_dbg(dev->dev, "Failed to read vlan table\n"); goto exit; } @@ -151,8 +141,8 @@ static int ksz9477_set_vlan_table(struct ksz_device *dev, u16 vid, ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); /* wait to be cleared */ - ret = ksz9477_wait_vlan_ctrl_ready(dev, VLAN_START, 1000); - if (ret < 0) { + ret = ksz9477_wait_vlan_ctrl_ready(dev); + if (ret) { dev_dbg(dev->dev, "Failed to write vlan table\n"); goto exit; } -- 2.20.1
[PATCH 4/5] net: dsa: microchip: Replace ksz9477_wait_alu_sta_ready polling with regmap
Regmap provides polling function to poll for bits in a register. This function is another reimplementation of polling for bit being clear in a register. Replace this with regmap polling function. Moreover, inline the function parameters, as the function is never called with any other parameter values than this one. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz9477.c | 32 +++-- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index e5b2f3e45db6..bfc44799854c 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -184,22 +184,14 @@ static int ksz9477_wait_alu_ready(struct ksz_device *dev) val, !(val & ALU_START), 10, 1000); } -static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, - int timeout) +static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev) { - u32 data; - - do { - ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data); - if (!(data & waiton)) - break; - usleep_range(1, 10); - } while (timeout-- > 0); - - if (timeout <= 0) - return -ETIMEDOUT; + unsigned int val; - return 0; + return regmap_read_poll_timeout(dev->regmap[2], + REG_SW_ALU_STAT_CTRL__4, + val, !(val & ALU_STAT_START), + 10, 1000); } static int ksz9477_reset_switch(struct ksz_device *dev) @@ -821,7 +813,7 @@ static void ksz9477_port_mdb_add(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); /* wait to be finished */ - if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) { + if (ksz9477_wait_alu_sta_ready(dev)) { dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); goto exit; } @@ -862,7 +854,7 @@ static void ksz9477_port_mdb_add(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); /* wait to be finished */ - if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) + if (ksz9477_wait_alu_sta_ready(dev)) dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); exit: @@ -892,8 +884,8 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); /* wait to be finished */ - ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000); - if (ret < 0) { + ret = ksz9477_wait_alu_sta_ready(dev); + if (ret) { dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); goto exit; } @@ -934,8 +926,8 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); /* wait to be finished */ - ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000); - if (ret < 0) + ret = ksz9477_wait_alu_sta_ready(dev); + if (ret) dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); exit: -- 2.20.1
[PATCH 5/5] net: dsa: microchip: Replace bit RMW with regmap
Regmap provides read-modify-write function to update bitfields in registers. Replace ad-hoc read-modify-write with regmap_update_bits() where applicable. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz9477.c | 22 ++ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index bfc44799854c..a8c97f7a79b7 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -197,16 +197,14 @@ static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev) static int ksz9477_reset_switch(struct ksz_device *dev) { u8 data8; - u16 data16; u32 data32; /* reset switch */ ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); /* turn off SPI DO Edge select */ - ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); - data8 &= ~SPI_AUTO_EDGE_DETECTION; - ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); + regmap_update_bits(dev->regmap[0], REG_SW_GLOBAL_SERIAL_CTRL_0, + SPI_AUTO_EDGE_DETECTION, 0); /* default configuration */ ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); @@ -220,10 +218,10 @@ static int ksz9477_reset_switch(struct ksz_device *dev) ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); /* set broadcast storm protection 10% rate */ - ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16); - data16 &= ~BROADCAST_STORM_RATE; - data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; - ksz_write16(dev, REG_SW_MAC_CTRL_2, data16); + regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2, + BROADCAST_STORM_RATE, + (BROADCAST_STORM_VALUE * + BROADCAST_STORM_PROT_RATE) / 100); if (dev->synclko_125) ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, @@ -485,10 +483,10 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) { u8 data; - ksz_read8(dev, REG_SW_LUE_CTRL_2, &data); - data &= ~(SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S); - data |= (SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); - ksz_write8(dev, REG_SW_LUE_CTRL_2, data); + regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2, + SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S, + SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); + if (port < dev->mib_port_cnt) { /* flush individual port */ ksz_pread8(dev, port, P_STP_CTRL, &data); -- 2.20.1
[PATCH 0/5] net: dsa: microchip: Further regmap cleanups
This patchset cleans up KSZ9477 switch driver by replacing various ad-hoc polling implementations and register RMW with regmap functions. Each polling function is replaced separately to make it easier to review and possibly bisect, but maybe the patches can be squashed. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh Marek Vasut (5): net: dsa: microchip: Replace ad-hoc polling with regmap net: dsa: microchip: Replace ksz9477_wait_vlan_ctrl_ready polling with regmap net: dsa: microchip: Replace ksz9477_wait_alu_ready polling with regmap net: dsa: microchip: Replace ksz9477_wait_alu_sta_ready polling with regmap net: dsa: microchip: Replace bit RMW with regmap drivers/net/dsa/microchip/ksz9477.c| 128 + drivers/net/dsa/microchip/ksz_common.h | 14 --- 2 files changed, 47 insertions(+), 95 deletions(-) -- 2.20.1
[PATCH 3/5] net: dsa: microchip: Replace ksz9477_wait_alu_ready polling with regmap
Regmap provides polling function to poll for bits in a register. This function is another reimplementation of polling for bit being clear in a register. Replace this with regmap polling function. Moreover, inline the function parameters, as the function is never called with any other parameter values than this one. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Tristram Ha Cc: Woojung Huh --- drivers/net/dsa/microchip/ksz9477.c | 34 ++--- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 0aab00bf23b9..e5b2f3e45db6 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -176,22 +176,12 @@ static void ksz9477_write_table(struct ksz_device *dev, u32 *table) ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); } -static int ksz9477_wait_alu_ready(struct ksz_device *dev, u32 waiton, - int timeout) +static int ksz9477_wait_alu_ready(struct ksz_device *dev) { - u32 data; - - do { - ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); - if (!(data & waiton)) - break; - usleep_range(1, 10); - } while (timeout-- > 0); - - if (timeout <= 0) - return -ETIMEDOUT; + unsigned int val; - return 0; + return regmap_read_poll_timeout(dev->regmap[2], REG_SW_ALU_CTRL__4, + val, !(val & ALU_START), 10, 1000); } static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, @@ -633,8 +623,8 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); /* wait to be finished */ - ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); - if (ret < 0) { + ret = ksz9477_wait_alu_ready(dev); + if (ret) { dev_dbg(dev->dev, "Failed to read ALU\n"); goto exit; } @@ -657,8 +647,8 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); /* wait to be finished */ - ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); - if (ret < 0) + ret = ksz9477_wait_alu_ready(dev); + if (ret) dev_dbg(dev->dev, "Failed to write ALU\n"); exit: @@ -690,8 +680,8 @@ static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); /* wait to be finished */ - ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); - if (ret < 0) { + ret = ksz9477_wait_alu_ready(dev); + if (ret) { dev_dbg(dev->dev, "Failed to read ALU\n"); goto exit; } @@ -724,8 +714,8 @@ static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); /* wait to be finished */ - ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000); - if (ret < 0) + ret = ksz9477_wait_alu_ready(dev); + if (ret) dev_dbg(dev->dev, "Failed to write ALU\n"); exit: -- 2.20.1
Re: [PATCH 0/5] net: dsa: microchip: Further regmap cleanups
On 6/28/19 5:31 PM, Vivien Didelot wrote: > Hi Marek, > > On Thu, 27 Jun 2019 23:55:51 +0200, Marek Vasut wrote: >> This patchset cleans up KSZ9477 switch driver by replacing various >> ad-hoc polling implementations and register RMW with regmap functions. >> >> Each polling function is replaced separately to make it easier to review >> and possibly bisect, but maybe the patches can be squashed. >> >> Signed-off-by: Marek Vasut >> Cc: Andrew Lunn >> Cc: Florian Fainelli >> Cc: Tristram Ha >> Cc: Woojung Huh > > Please copy me next time, as per the MAINTAINERS file. Will do. I plan to submit KSZ8795 support next. -- Best regards, Marek Vasut
[PATCH V5] net: phy: tja11xx: Add TJA11xx PHY driver
Add driver for the NXP TJA1100 and TJA1101 PHYs. These PHYs are special BroadRReach 100BaseT1 PHYs used in automotive. Signed-off-by: Marek Vasut Cc: Andrew Lunn Cc: Florian Fainelli Cc: Guenter Roeck Cc: Heiner Kallweit Cc: Jean Delvare Cc: linux-hw...@vger.kernel.org --- V2: - Use phy_modify(), phy_{set,clear}_bits() - Drop enable argument of tja11xx_enable_link_control() - Use PHY_BASIC_T1_FEATURES and dont modify supported/advertised features in config_init callback - Use genphy_soft_reset() instead of opencoding the reset sequence. - Drop the aneg parts, since the PHY datasheet claims it does not support aneg V3: - Replace clr with mask - Add hwmon support - Check commstat in tja11xx_read_status() only if link is up - Use PHY_ID_MATCH_MODEL() V4: - Use correct bit in tja11xx_hwmon_read() hwmon_temp_crit_alarm - Use ENOMEM if devm_kstrdup() fails - Check $type in tja11xx_hwmon_read() in addition to $attr V5: - Drop assignment of phydev->irq,pause,asym_pause --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/nxp-tja11xx.c | 423 ++ 3 files changed, 430 insertions(+) create mode 100644 drivers/net/phy/nxp-tja11xx.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d6299710d634..31478d8b3c0c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -415,6 +415,12 @@ config NATIONAL_PHY ---help--- Currently supports the DP83865 PHY. +config NXP_TJA11XX_PHY + tristate "NXP TJA11xx PHYs support" + depends on HWMON + ---help--- + Currently supports the NXP TJA1100 and TJA1101 PHY. + config QSEMI_PHY tristate "Quality Semiconductor PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 27d7f9f3b0de..bac339e09042 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_MICROCHIP_PHY) += microchip.o obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o obj-$(CONFIG_MICROSEMI_PHY)+= mscc.o obj-$(CONFIG_NATIONAL_PHY) += national.o +obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-$(CONFIG_QSEMI_PHY)+= qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c new file mode 100644 index ..11b8701e78fd --- /dev/null +++ b/drivers/net/phy/nxp-tja11xx.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 +/* NXP TJA1100 BroadRReach PHY driver + * + * Copyright (C) 2018 Marek Vasut + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHY_ID_MASK0xfff0 +#define PHY_ID_TJA1100 0x0180dc40 +#define PHY_ID_TJA1101 0x0180dd00 + +#define MII_ECTRL 17 +#define MII_ECTRL_LINK_CONTROL BIT(15) +#define MII_ECTRL_POWER_MODE_MASK GENMASK(14, 11) +#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11) +#define MII_ECTRL_POWER_MODE_NORMAL(0x3 << 11) +#define MII_ECTRL_POWER_MODE_STANDBY (0xc << 11) +#define MII_ECTRL_CONFIG_ENBIT(2) +#define MII_ECTRL_WAKE_REQUEST BIT(0) + +#define MII_CFG1 18 +#define MII_CFG1_AUTO_OP BIT(14) +#define MII_CFG1_SLEEP_CONFIRM BIT(6) +#define MII_CFG1_LED_MODE_MASK GENMASK(5, 4) +#define MII_CFG1_LED_MODE_LINKUP 0 +#define MII_CFG1_LED_ENABLEBIT(3) + +#define MII_CFG2 19 +#define MII_CFG2_SLEEP_REQUEST_TO GENMASK(1, 0) +#define MII_CFG2_SLEEP_REQUEST_TO_16MS 0x3 + +#define MII_INTSRC 21 +#define MII_INTSRC_TEMP_ERRBIT(1) +#define MII_INTSRC_UV_ERR BIT(3) + +#define MII_COMMSTAT 23 +#define MII_COMMSTAT_LINK_UP BIT(15) + +#define MII_GENSTAT24 +#define MII_GENSTAT_PLL_LOCKED BIT(14) + +#define MII_COMMCFG27 +#define MII_COMMCFG_AUTO_OPBIT(15) + +struct tja11xx_priv { + char*hwmon_name; + struct device *hwmon_dev; +}; + +struct tja11xx_phy_stats { + const char *string; + u8 reg; + u8 off; + u16 mask; +}; + +static struct tja11xx_phy_stats tja11xx_hw_stats[] = { + { "phy_symbol_error_count", 20, 0, GENMASK(15, 0) }, + { "phy_polarity_detect", 25, 6, BIT(6) }, + { "phy_open_detect", 25, 7, BIT(7) }, + { "phy_short_detect", 25, 8, BIT(8) }, + { "phy_rem_rcvr_count", 26, 0, GENMASK(7, 0) }, + { "phy_loc_rcvr_count", 26, 8, GENMASK(15, 8) }, +}; + +static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set) +{