* [RFC net-next 0/2] DSA driver for Realtek RTL8366S/SR @ 2021-02-17 6:21 DENG Qingfang 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang 0 siblings, 2 replies; 17+ messages in thread From: DENG Qingfang @ 2021-02-17 6:21 UTC (permalink / raw) To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski Cc: netdev, Linus Walleij, Mauri Sandberg Add DSA driver and tag for Realtek RTL8366S/SR. Posting this as RFC because Linus Walleij told me that Mauri Sandberg was working on this driver too, and some of the features are not yet tested. DENG Qingfang (2): net: dsa: add Realtek RTL8366S switch tag net: dsa: add Realtek RTL8366S switch driver drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/Makefile | 2 +- drivers/net/dsa/realtek-smi-core.c | 3 +- drivers/net/dsa/realtek-smi-core.h | 1 + drivers/net/dsa/rtl8366s.c | 1165 ++++++++++++++++++++++++++++ include/net/dsa.h | 2 + net/dsa/Kconfig | 6 + net/dsa/Makefile | 1 + net/dsa/tag_rtl8366s.c | 98 +++ 9 files changed, 1276 insertions(+), 3 deletions(-) create mode 100644 drivers/net/dsa/rtl8366s.c create mode 100644 net/dsa/tag_rtl8366s.c -- 2.25.1 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 6:21 [RFC net-next 0/2] DSA driver for Realtek RTL8366S/SR DENG Qingfang @ 2021-02-17 6:21 ` DENG Qingfang 2021-02-17 7:07 ` Heiner Kallweit ` (2 more replies) 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang 1 sibling, 3 replies; 17+ messages in thread From: DENG Qingfang @ 2021-02-17 6:21 UTC (permalink / raw) To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski Cc: netdev, Linus Walleij, Mauri Sandberg Add support for Realtek RTL8366S switch tag Signed-off-by: DENG Qingfang <dqfext@gmail.com> --- include/net/dsa.h | 2 + net/dsa/Kconfig | 6 +++ net/dsa/Makefile | 1 + net/dsa/tag_rtl8366s.c | 98 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 net/dsa/tag_rtl8366s.c diff --git a/include/net/dsa.h b/include/net/dsa.h index 83a933e563fe..14fedf832f27 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -49,6 +49,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_XRS700X_VALUE 19 #define DSA_TAG_PROTO_OCELOT_8021Q_VALUE 20 #define DSA_TAG_PROTO_SEVILLE_VALUE 21 +#define DSA_TAG_PROTO_RTL8366S_VALUE 22 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -73,6 +74,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_XRS700X = DSA_TAG_PROTO_XRS700X_VALUE, DSA_TAG_PROTO_OCELOT_8021Q = DSA_TAG_PROTO_OCELOT_8021Q_VALUE, DSA_TAG_PROTO_SEVILLE = DSA_TAG_PROTO_SEVILLE_VALUE, + DSA_TAG_PROTO_RTL8366S = DSA_TAG_PROTO_RTL8366S_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index a45572cfb71a..303228e0ad8b 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -104,6 +104,12 @@ config NET_DSA_TAG_RTL4_A Realtek switches with 4 byte protocol A tags, sich as found in the Realtek RTL8366RB. +config NET_DSA_TAG_RTL8366S + tristate "Tag driver for Realtek RTL8366S switch tags" + help + Say Y or M if you want to enable support for tagging frames for the + Realtek RTL8366S switch. + config NET_DSA_TAG_OCELOT tristate "Tag driver for Ocelot family of switches, using NPI port" select PACKING diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 44bc79952b8b..df158e73a30b 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o +obj-$(CONFIG_NET_DSA_TAG_RTL8366S) += tag_rtl8366s.o obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o diff --git a/net/dsa/tag_rtl8366s.c b/net/dsa/tag_rtl8366s.c new file mode 100644 index 000000000000..6c6c66853e4c --- /dev/null +++ b/net/dsa/tag_rtl8366s.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Handler for Realtek RTL8366S switch tags + * Copyright (c) 2021 DENG, Qingfang <dqfext@gmail.com> + * + * This tag header looks like: + * + * ------------------------------------------------- + * | MAC DA | MAC SA | 0x8899 | 2-byte tag | Type | + * ------------------------------------------------- + * + * The 2-byte tag format in tag_rcv: + * +------+------+------+------+------+------+------+------+ + * 15: 8 | Protocol number (0x9) | Priority | Reserved | + * +------+------+------+------+------+------+------+------+ + * 7: 0 | Reserved | Source port number | + * +------+------+------+------+------+------+------+------+ + * + * The 2-byte tag format in tag_xmit: + * +------+------+------+------+------+------+------+------+ + * 15: 8 | Protocol number (0x9) | Priority | Reserved | + * +------+------+------+------+------+------+------+------+ + * 7: 0 | Reserved | Destination port mask | + * +------+------+------+------+------+------+------+------+ + */ + +#include <linux/etherdevice.h> + +#include "dsa_priv.h" + +#define RTL8366S_HDR_LEN 4 +#define RTL8366S_ETHERTYPE 0x8899 +#define RTL8366S_PROTOCOL_SHIFT 12 +#define RTL8366S_PROTOCOL 0x9 +#define RTL8366S_TAG \ + (RTL8366S_PROTOCOL << RTL8366S_PROTOCOL_SHIFT) + +static struct sk_buff *rtl8366s_tag_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + __be16 *tag; + + /* Make sure the frame is at least 60 bytes long _before_ + * inserting the CPU tag, or it will be dropped by the switch. + */ + if (unlikely(eth_skb_pad(skb))) + return NULL; + + skb_push(skb, RTL8366S_HDR_LEN); + memmove(skb->data, skb->data + RTL8366S_HDR_LEN, + 2 * ETH_ALEN); + + tag = (__be16 *)(skb->data + 2 * ETH_ALEN); + tag[0] = htons(RTL8366S_ETHERTYPE); + tag[1] = htons(RTL8366S_TAG | BIT(dp->index)); + + return skb; +} + +static struct sk_buff *rtl8366s_tag_rcv(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt) +{ + u8 *tag; + u8 port; + + if (unlikely(!pskb_may_pull(skb, RTL8366S_HDR_LEN))) + return NULL; + + tag = skb->data - 2; + port = tag[3] & 0x7; + + skb->dev = dsa_master_find_slave(dev, 0, port); + if (unlikely(!skb->dev)) + return NULL; + + skb_pull_rcsum(skb, RTL8366S_HDR_LEN); + memmove(skb->data - ETH_HLEN, + skb->data - ETH_HLEN - RTL8366S_HDR_LEN, + 2 * ETH_ALEN); + + skb->offload_fwd_mark = 1; + + return skb; +} + +static const struct dsa_device_ops rtl8366s_netdev_ops = { + .name = "rtl8366s", + .proto = DSA_TAG_PROTO_RTL8366S, + .xmit = rtl8366s_tag_xmit, + .rcv = rtl8366s_tag_rcv, + .overhead = RTL8366S_HDR_LEN, +}; +module_dsa_tag_driver(rtl8366s_netdev_ops); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8366S); -- 2.25.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang @ 2021-02-17 7:07 ` Heiner Kallweit 2021-02-17 11:01 ` Linus Walleij 2021-02-17 10:55 ` Linus Walleij 2021-02-27 23:47 ` Linus Walleij 2 siblings, 1 reply; 17+ messages in thread From: Heiner Kallweit @ 2021-02-17 7:07 UTC (permalink / raw) To: DENG Qingfang, Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski Cc: netdev, Linus Walleij, Mauri Sandberg On 17.02.2021 07:21, DENG Qingfang wrote: > Add support for Realtek RTL8366S switch tag > > Signed-off-by: DENG Qingfang <dqfext@gmail.com> > --- > include/net/dsa.h | 2 + > net/dsa/Kconfig | 6 +++ > net/dsa/Makefile | 1 + > net/dsa/tag_rtl8366s.c | 98 ++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 107 insertions(+) > create mode 100644 net/dsa/tag_rtl8366s.c > > diff --git a/include/net/dsa.h b/include/net/dsa.h > index 83a933e563fe..14fedf832f27 100644 > --- a/include/net/dsa.h > +++ b/include/net/dsa.h > @@ -49,6 +49,7 @@ struct phylink_link_state; > #define DSA_TAG_PROTO_XRS700X_VALUE 19 > #define DSA_TAG_PROTO_OCELOT_8021Q_VALUE 20 > #define DSA_TAG_PROTO_SEVILLE_VALUE 21 > +#define DSA_TAG_PROTO_RTL8366S_VALUE 22 > > enum dsa_tag_protocol { > DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, > @@ -73,6 +74,7 @@ enum dsa_tag_protocol { > DSA_TAG_PROTO_XRS700X = DSA_TAG_PROTO_XRS700X_VALUE, > DSA_TAG_PROTO_OCELOT_8021Q = DSA_TAG_PROTO_OCELOT_8021Q_VALUE, > DSA_TAG_PROTO_SEVILLE = DSA_TAG_PROTO_SEVILLE_VALUE, > + DSA_TAG_PROTO_RTL8366S = DSA_TAG_PROTO_RTL8366S_VALUE, > }; > > struct packet_type; > diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig > index a45572cfb71a..303228e0ad8b 100644 > --- a/net/dsa/Kconfig > +++ b/net/dsa/Kconfig > @@ -104,6 +104,12 @@ config NET_DSA_TAG_RTL4_A > Realtek switches with 4 byte protocol A tags, sich as found in > the Realtek RTL8366RB. > > +config NET_DSA_TAG_RTL8366S > + tristate "Tag driver for Realtek RTL8366S switch tags" > + help > + Say Y or M if you want to enable support for tagging frames for the > + Realtek RTL8366S switch. > + > config NET_DSA_TAG_OCELOT > tristate "Tag driver for Ocelot family of switches, using NPI port" > select PACKING > diff --git a/net/dsa/Makefile b/net/dsa/Makefile > index 44bc79952b8b..df158e73a30b 100644 > --- a/net/dsa/Makefile > +++ b/net/dsa/Makefile > @@ -12,6 +12,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o > obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o > obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o > obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o > +obj-$(CONFIG_NET_DSA_TAG_RTL8366S) += tag_rtl8366s.o > obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o > obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o > obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o > diff --git a/net/dsa/tag_rtl8366s.c b/net/dsa/tag_rtl8366s.c > new file mode 100644 > index 000000000000..6c6c66853e4c > --- /dev/null > +++ b/net/dsa/tag_rtl8366s.c > @@ -0,0 +1,98 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Handler for Realtek RTL8366S switch tags > + * Copyright (c) 2021 DENG, Qingfang <dqfext@gmail.com> > + * > + * This tag header looks like: > + * > + * ------------------------------------------------- > + * | MAC DA | MAC SA | 0x8899 | 2-byte tag | Type | > + * ------------------------------------------------- > + * > + * The 2-byte tag format in tag_rcv: > + * +------+------+------+------+------+------+------+------+ > + * 15: 8 | Protocol number (0x9) | Priority | Reserved | > + * +------+------+------+------+------+------+------+------+ > + * 7: 0 | Reserved | Source port number | > + * +------+------+------+------+------+------+------+------+ > + * > + * The 2-byte tag format in tag_xmit: > + * +------+------+------+------+------+------+------+------+ > + * 15: 8 | Protocol number (0x9) | Priority | Reserved | > + * +------+------+------+------+------+------+------+------+ > + * 7: 0 | Reserved | Destination port mask | > + * +------+------+------+------+------+------+------+------+ > + */ > + > +#include <linux/etherdevice.h> > + > +#include "dsa_priv.h" > + > +#define RTL8366S_HDR_LEN 4 > +#define RTL8366S_ETHERTYPE 0x8899 I found this protocol referenced as Realtek Remote Control Protocol (RRCP) and it seems to be used by few Realtek chips. Not sure whether this protocol is officially registered. If yes, then it should be added to the list of ethernet protocol id's in include/uapi/linux/if_ether.h. If not, then it may be better to define it using the usual naming scheme as ETH_P_RRCP in realtek-smi-core.h. > +#define RTL8366S_PROTOCOL_SHIFT 12 > +#define RTL8366S_PROTOCOL 0x9 > +#define RTL8366S_TAG \ > + (RTL8366S_PROTOCOL << RTL8366S_PROTOCOL_SHIFT) > + > +static struct sk_buff *rtl8366s_tag_xmit(struct sk_buff *skb, > + struct net_device *dev) > +{ > + struct dsa_port *dp = dsa_slave_to_port(dev); > + __be16 *tag; > + > + /* Make sure the frame is at least 60 bytes long _before_ > + * inserting the CPU tag, or it will be dropped by the switch. > + */ > + if (unlikely(eth_skb_pad(skb))) > + return NULL; > + > + skb_push(skb, RTL8366S_HDR_LEN); > + memmove(skb->data, skb->data + RTL8366S_HDR_LEN, > + 2 * ETH_ALEN); > + > + tag = (__be16 *)(skb->data + 2 * ETH_ALEN); > + tag[0] = htons(RTL8366S_ETHERTYPE); > + tag[1] = htons(RTL8366S_TAG | BIT(dp->index)); > + > + return skb; > +} > + > +static struct sk_buff *rtl8366s_tag_rcv(struct sk_buff *skb, > + struct net_device *dev, > + struct packet_type *pt) > +{ > + u8 *tag; > + u8 port; > + > + if (unlikely(!pskb_may_pull(skb, RTL8366S_HDR_LEN))) > + return NULL; > + > + tag = skb->data - 2; > + port = tag[3] & 0x7; > + > + skb->dev = dsa_master_find_slave(dev, 0, port); > + if (unlikely(!skb->dev)) > + return NULL; > + > + skb_pull_rcsum(skb, RTL8366S_HDR_LEN); > + memmove(skb->data - ETH_HLEN, > + skb->data - ETH_HLEN - RTL8366S_HDR_LEN, > + 2 * ETH_ALEN); > + > + skb->offload_fwd_mark = 1; > + > + return skb; > +} > + > +static const struct dsa_device_ops rtl8366s_netdev_ops = { > + .name = "rtl8366s", > + .proto = DSA_TAG_PROTO_RTL8366S, > + .xmit = rtl8366s_tag_xmit, > + .rcv = rtl8366s_tag_rcv, > + .overhead = RTL8366S_HDR_LEN, > +}; > +module_dsa_tag_driver(rtl8366s_netdev_ops); > + > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8366S); > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 7:07 ` Heiner Kallweit @ 2021-02-17 11:01 ` Linus Walleij 2021-02-17 11:28 ` Heiner Kallweit 0 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2021-02-17 11:01 UTC (permalink / raw) To: Heiner Kallweit Cc: DENG Qingfang, Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 8:08 AM Heiner Kallweit <hkallweit1@gmail.com> wrote: > > +#define RTL8366S_HDR_LEN 4 > > +#define RTL8366S_ETHERTYPE 0x8899 > > I found this protocol referenced as Realtek Remote Control Protocol (RRCP) > and it seems to be used by few Realtek chips. Not sure whether this > protocol is officially registered. If yes, then it should be added to > the list of ethernet protocol id's in include/uapi/linux/if_ether.h. > If not, then it may be better to define it using the usual naming > scheme as ETH_P_RRCP in realtek-smi-core.h. It's actually quite annoying, Realtek use type 0x8899 for all their custom stuff, including RRCP and internal DSA tagging inside switches, which are two completely different use cases. When I expose raw DSA frames to wireshark it identifies it as "Realtek RRCP" and then naturally cannot decode the frames since this is not RRCP but another protocol identified by the same ethertype. Inside DSA it works as we explicitly asks tells the kernel using the tagging code in net/dsa/tag_rtl4_a.c that this is the DSA version of ethertype 0x8899 and it then goes to dissect the actual 4 bytes tag. There are at least four protocols out there using ethertype 0x8899. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 11:01 ` Linus Walleij @ 2021-02-17 11:28 ` Heiner Kallweit 0 siblings, 0 replies; 17+ messages in thread From: Heiner Kallweit @ 2021-02-17 11:28 UTC (permalink / raw) To: Linus Walleij Cc: DENG Qingfang, Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On 17.02.2021 12:01, Linus Walleij wrote: > On Wed, Feb 17, 2021 at 8:08 AM Heiner Kallweit <hkallweit1@gmail.com> wrote: > >>> +#define RTL8366S_HDR_LEN 4 >>> +#define RTL8366S_ETHERTYPE 0x8899 >> >> I found this protocol referenced as Realtek Remote Control Protocol (RRCP) >> and it seems to be used by few Realtek chips. Not sure whether this >> protocol is officially registered. If yes, then it should be added to >> the list of ethernet protocol id's in include/uapi/linux/if_ether.h. >> If not, then it may be better to define it using the usual naming >> scheme as ETH_P_RRCP in realtek-smi-core.h. > > It's actually quite annoying, Realtek use type 0x8899 for all their > custom stuff, including RRCP and internal DSA tagging inside > switches, which are two completely different use cases. > > When I expose raw DSA frames to wireshark it identifies it > as "Realtek RRCP" and then naturally cannot decode the > frames since this is not RRCP but another protocol identified > by the same ethertype. > > Inside DSA it works as we explicitly asks tells the kernel using the > tagging code in net/dsa/tag_rtl4_a.c that this is the DSA version > of ethertype 0x8899 and it then goes to dissect the actual > 4 bytes tag. > > There are at least four protocols out there using ethertype 0x8899. > Ugly .. Thanks for the details! > Yours, > Linus Walleij > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang 2021-02-17 7:07 ` Heiner Kallweit @ 2021-02-17 10:55 ` Linus Walleij 2021-02-17 12:28 ` DENG Qingfang 2021-02-27 23:47 ` Linus Walleij 2 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2021-02-17 10:55 UTC (permalink / raw) To: DENG Qingfang Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 7:21 AM DENG Qingfang <dqfext@gmail.com> wrote: > Add support for Realtek RTL8366S switch tag > > Signed-off-by: DENG Qingfang <dqfext@gmail.com> I suppose this switch can just use the existing RTL4 A tag code after the recent patch so this one is not needed? Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 10:55 ` Linus Walleij @ 2021-02-17 12:28 ` DENG Qingfang 0 siblings, 0 replies; 17+ messages in thread From: DENG Qingfang @ 2021-02-17 12:28 UTC (permalink / raw) To: Linus Walleij Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 6:55 PM Linus Walleij <linus.walleij@linaro.org> wrote: > > I suppose this switch can just use the existing RTL4 A tag > code after the recent patch so this one is not needed? No. Different protocol (0x9 instead of 0xA) and different xmit tag format (port bit mask instead of port number). Please take a closer look. > > Yours, > Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang 2021-02-17 7:07 ` Heiner Kallweit 2021-02-17 10:55 ` Linus Walleij @ 2021-02-27 23:47 ` Linus Walleij 2021-02-28 11:32 ` DENG Qingfang 2 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2021-02-27 23:47 UTC (permalink / raw) To: DENG Qingfang Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 7:21 AM DENG Qingfang <dqfext@gmail.com> wrote: > Add support for Realtek RTL8366S switch tag > > Signed-off-by: DENG Qingfang <dqfext@gmail.com> I understand this switch tag now sorry for confusion. > @@ -104,6 +104,12 @@ config NET_DSA_TAG_RTL4_A > Realtek switches with 4 byte protocol A tags, sich as found in > the Realtek RTL8366RB. > > +config NET_DSA_TAG_RTL8366S > + tristate "Tag driver for Realtek RTL8366S switch tags" > + help > + Say Y or M if you want to enable support for tagging frames for the > + Realtek RTL8366S switch. I names the previous protocol "RTL4 A" after a 4-byte tag with protocol indicted as "A", what about naming this "RTL2 9" in the same vein? It will be good if some other switch is using the same protocol. (If any...) > obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o > +obj-$(CONFIG_NET_DSA_TAG_RTL8366S) += tag_rtl8366s.o So tag_rtl2_9.o etc. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-27 23:47 ` Linus Walleij @ 2021-02-28 11:32 ` DENG Qingfang 2021-03-01 13:06 ` Linus Walleij 0 siblings, 1 reply; 17+ messages in thread From: DENG Qingfang @ 2021-02-28 11:32 UTC (permalink / raw) To: Linus Walleij Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Sun, Feb 28, 2021 at 7:47 AM Linus Walleij <linus.walleij@linaro.org> wrote: > > I names the previous protocol "RTL4 A" after a 4-byte tag > with protocol indicted as "A", what about naming this > "RTL2 9" in the same vein? It will be good if some other > switch is using the same protocol. (If any...) RTL8306 uses 0x9 too, but the tag format is different... > > > obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o > > +obj-$(CONFIG_NET_DSA_TAG_RTL8366S) += tag_rtl8366s.o > > So tag_rtl2_9.o etc. > > Yours, > Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag 2021-02-28 11:32 ` DENG Qingfang @ 2021-03-01 13:06 ` Linus Walleij 0 siblings, 0 replies; 17+ messages in thread From: Linus Walleij @ 2021-03-01 13:06 UTC (permalink / raw) To: DENG Qingfang Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Sun, Feb 28, 2021 at 12:32 PM DENG Qingfang <dqfext@gmail.com> wrote: > On Sun, Feb 28, 2021 at 7:47 AM Linus Walleij <linus.walleij@linaro.org> wrote: > > > > I names the previous protocol "RTL4 A" after a 4-byte tag > > with protocol indicted as "A", what about naming this > > "RTL2 9" in the same vein? It will be good if some other > > switch is using the same protocol. (If any...) > > RTL8306 uses 0x9 too, but the tag format is different... Oh what a mess. :O OK go with this. Maybe I should rename my tagger to tag_rtl8366rb.c instead... Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 6:21 [RFC net-next 0/2] DSA driver for Realtek RTL8366S/SR DENG Qingfang 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang @ 2021-02-17 6:21 ` DENG Qingfang 2021-02-17 7:37 ` kernel test robot ` (3 more replies) 1 sibling, 4 replies; 17+ messages in thread From: DENG Qingfang @ 2021-02-17 6:21 UTC (permalink / raw) To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski Cc: netdev, Linus Walleij, Mauri Sandberg Support Realtek RTL8366S/SR switch Signed-off-by: DENG Qingfang <dqfext@gmail.com> --- drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/Makefile | 2 +- drivers/net/dsa/realtek-smi-core.c | 3 +- drivers/net/dsa/realtek-smi-core.h | 1 + drivers/net/dsa/rtl8366s.c | 1165 ++++++++++++++++++++++++++++ 5 files changed, 1169 insertions(+), 3 deletions(-) create mode 100644 drivers/net/dsa/rtl8366s.c diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 3af373e90806..52f1df6ef53a 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -75,6 +75,7 @@ config NET_DSA_REALTEK_SMI tristate "Realtek SMI Ethernet switch family support" depends on NET_DSA select NET_DSA_TAG_RTL4_A + select NET_DSA_TAG_RTL8366S select FIXED_PHY select IRQ_DOMAIN select REALTEK_PHY diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index f3598c040994..8c51c25d8378 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o -realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o +realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o rtl8366s.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o diff --git a/drivers/net/dsa/realtek-smi-core.c b/drivers/net/dsa/realtek-smi-core.c index 8e49d4f85d48..e0ced416c362 100644 --- a/drivers/net/dsa/realtek-smi-core.c +++ b/drivers/net/dsa/realtek-smi-core.c @@ -480,9 +480,8 @@ static const struct of_device_id realtek_smi_of_match[] = { .data = &rtl8366rb_variant, }, { - /* FIXME: add support for RTL8366S and more */ .compatible = "realtek,rtl8366s", - .data = NULL, + .data = &rtl8366s_variant, }, { /* sentinel */ }, }; diff --git a/drivers/net/dsa/realtek-smi-core.h b/drivers/net/dsa/realtek-smi-core.h index fcf465f7f922..a5d45b6f6de3 100644 --- a/drivers/net/dsa/realtek-smi-core.h +++ b/drivers/net/dsa/realtek-smi-core.h @@ -143,5 +143,6 @@ int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset); void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); extern const struct realtek_smi_variant rtl8366rb_variant; +extern const struct realtek_smi_variant rtl8366s_variant; #endif /* _REALTEK_SMI_H */ diff --git a/drivers/net/dsa/rtl8366s.c b/drivers/net/dsa/rtl8366s.c new file mode 100644 index 000000000000..718e492f8bbd --- /dev/null +++ b/drivers/net/dsa/rtl8366s.c @@ -0,0 +1,1165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Realtek SMI subdriver for the Realtek RTL8366S ethernet switch + * + * Copyright (C) 2021 DENG, Qingfang <dqfext@gmail.com> + * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> + */ + +#include <linux/bitfield.h> +#include <linux/etherdevice.h> +#include <linux/if_bridge.h> +#include <linux/regmap.h> + +#include "realtek-smi-core.h" + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366S_SGCR 0x0000 +#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) +#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) +#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) +#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_EN_VLAN BIT(13) + +/* Port Enable Control register */ +#define RTL8366S_PECR 0x0001 + +/* Switch Security Control registers */ +#define RTL8366S_SSCR0 0x0002 +#define RTL8366S_SSCR1 0x0003 +#define RTL8366S_SSCR2 0x0004 +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) + +/* Port Mode Control registers */ +#define RTL8366S_PMC0 0x0005 +#define RTL8366S_PMC0_SPI BIT(0) +#define RTL8366S_PMC0_EN_AUTOLOAD BIT(1) +#define RTL8366S_PMC0_PROBE BIT(2) +#define RTL8366S_PMC0_DIS_BISR BIT(3) +#define RTL8366S_PMC0_ADCTEST BIT(4) +#define RTL8366S_PMC0_SRAM_DIAG BIT(5) +#define RTL8366S_PMC0_EN_SCAN BIT(6) +#define RTL8366S_PMC0_P4_IOMODE_MASK GENMASK(9, 7) +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_GMAC \ + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 0) +#define RTL8366S_PMC0_P4_IOMODE_GMAC_TO_RGMII \ + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 1) +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_RGMII \ + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 2) +#define RTL8366S_PMC0_P5_IOMODE_MASK GENMASK(12, 10) +#define RTL8366S_PMC0_SDSMODE_MASK GENMASK(15, 13) +#define RTL8366S_PMC1 0x0006 + +/* Port Mirror Control Register */ +#define RTL8366S_PMCR 0x0007 +#define RTL8366S_PMCR_SOURCE_MASK GENMASK(3, 0) +#define RTL8366S_PMCR_MINITOR_MASK GENMASK(7, 4) +#define RTL8366S_PMCR_MIRROR_RX BIT(8) +#define RTL8366S_PMCR_MIRROR_TX BIT(9) +#define RTL8366S_PMCR_MIRROR_SPC BIT(10) +#define RTL8366S_PMCR_MIRROR_ISO BIT(11) + +/* Keep format on egress */ +#define RTL8366S_EGRESS_KEEP_FORMAT_REG 0x0008 +#define RTL8366S_EGRESS_KEEP_FORMAT_MASK GENMASK(15, 8) +#define RTL8366S_EGRESS_KEEP_FORMAT_ALL \ + FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, RTL8366S_PORT_ALL) + +/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */ +#define RTL8366S_GREEN_ETHERNET_CTRL_REG 0x000a +#define RTL8366S_GREEN_ETHERNET_CTRL_MASK 0x0018 +#define RTL8366S_GREEN_ETHERNET_TX BIT(3) +#define RTL8366S_GREEN_ETHERNET_RX BIT(4) + +/* bits 0..7 = port 0, bits 8..15 = port 1 */ +#define RTL8366S_PAACR0 0x0011 +/* bits 0..7 = port 2, bits 8..15 = port 3 */ +#define RTL8366S_PAACR1 0x0012 +/* bits 0..7 = port 4, bits 8..15 = port 5 */ +#define RTL8366S_PAACR2 0x0013 +#define RTL8366S_PAACR_SPEED_10M 0 +#define RTL8366S_PAACR_SPEED_100M 1 +#define RTL8366S_PAACR_SPEED_1000M 2 +#define RTL8366S_PAACR_FULL_DUPLEX BIT(2) +#define RTL8366S_PAACR_LINK_UP BIT(4) +#define RTL8366S_PAACR_TX_PAUSE BIT(5) +#define RTL8366S_PAACR_RX_PAUSE BIT(6) +#define RTL8366S_PAACR_AN BIT(7) + +#define RTL8366S_PAACR_CPU_PORT (RTL8366S_PAACR_SPEED_1000M | \ + RTL8366S_PAACR_FULL_DUPLEX | \ + RTL8366S_PAACR_LINK_UP | \ + RTL8366S_PAACR_TX_PAUSE | \ + RTL8366S_PAACR_RX_PAUSE) + +/* Spanning Tree Protocol register */ +#define RTL8366S_STP_BASE 0x003a +#define RTL8366S_STP_REG(_p) \ + (RTL8366S_STP_BASE + (_p)) +#define RTL8366S_STP_MASK GENMASK(1, 0) + +enum RTL8366S_STP_STATE +{ + RTL8366S_STP_DISABLED = 0, + RTL8366S_STP_BLOCKING, + RTL8366S_STP_LEARNING, + RTL8366S_STP_FORWARDING, +}; + +#define RTL8366S_CPU_CTRL_REG 0x004f +#define RTL8366S_CPU_DROP_UNKNOWN_DA BIT(14) +#define RTL8366S_CPU_NO_TAG BIT(15) + +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 + +#define RTL8366S_RESET_CTRL_REG 0x0100 +#define RTL8366S_CHIP_CTRL_RESET_HW BIT(0) +#define RTL8366S_CHIP_CTRL_RESET_SW BIT(1) + +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 +#define RTL8366S_CHIP_VERSION_MASK 0xf +#define RTL8366S_CHIP_ID_REG 0x0105 +#define RTL8366S_CHIP_ID_8366 0x8366 + +/* VLAN 4K access registers */ +#define RTL8366S_VLAN_TB_CTRL_REG 0x010f + +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 + +/* VLAN filtering registers */ +#define RTL8366S_VLAN_TAGINGRESS_REG 0x0378 +#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 + +/* Link aggregation registers */ +#define RTL8366S_LAGCR 0x0380 +#define RTL8366S_LAGCR_MODE_DUMP BIT(0) +#define RTL8366S_LAGCR_HASHSEL_MASK GENMASK(2, 1) +#define RTL8366S_LAGCR_HASHSEL_DA_SA \ + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 0) +#define RTL8366S_LAGCR_HASHSEL_DA \ + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 1) +#define RTL8366S_LAGCR_HASHSEL_SA \ + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 2) +#define RTL8366S_LAGCR_PORTMAP_MASK GENMASK(8, 3) + +#define RTL8366S_LAG_MAPPING_BASE 0x0381 +#define RTL8366S_LAG_MAPPING_BIT 3 +#define RTL8366S_LAG_MAPPING_MASK GENMASK(2, 0) + +#define RTL8366S_LAG_FC_CTRL_REG 0x0383 +#define RTL8366S_LAG_FC_MASK GENMASK(5, 0) + +#define RTL8366S_LAG_QEMPTY_REG 0x0384 +#define RTL8366S_LAG_QEMPTY_MASK GENMASK(5, 0) + +/* RMA register address */ +#define RTL8366S_RMA_CONTROL_REG 0x0391 +#define RTL8366S_RMA_IGMP BIT(10) +#define RTL8366S_RMA_MLD BIT(11) +#define RTL8366S_RMA_USER_DEFINED_BASE 0x0392 + +/* LED control registers */ +#define RTL8366S_LED_BLINKRATE_REG 0x0420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366S_LED_CTRL_REG 0x0421 +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 + +#define RTL8366S_MIB_COUNT 33 +#define RTL8366S_GLOBAL_MIB_COUNT 1 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 +#define RTL8366S_MIB_COUNTER_BASE 0x1000 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 +#define RTL8366S_MIB_COUNTER_BASE2 0x1180 +#define RTL8366S_MIB_CTRL_REG 0x11F0 +#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 + +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC + + +#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) + +#define RTL8366S_MAC_FORCE_CTRL0_REG 0x0F04 +#define RTL8366S_MAC_FORCE_CTRL1_REG 0x0F05 + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PORT_NUM_CPU 5 +#define RTL8366S_NUM_PORTS 6 +#define RTL8366S_NUM_VLANS 16 +#define RTL8366S_NUM_LEDGROUPS 4 +#define RTL8366S_NUM_VIDS 4096 +#define RTL8366S_PRIORITYMAX 7 +#define RTL8366S_FIDMAX 7 + + +#define RTL8366S_PORT_1 BIT(0) /* In userspace port 0 */ +#define RTL8366S_PORT_2 BIT(1) /* In userspace port 1 */ +#define RTL8366S_PORT_3 BIT(2) /* In userspace port 2 */ +#define RTL8366S_PORT_4 BIT(3) /* In userspace port 3 */ +#define RTL8366S_PORT_5 BIT(4) /* In userspace port 4 */ +#define RTL8366S_PORT_CPU BIT(5) /* CPU port */ + +#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_5 | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_5) + +#define RTL8366S_PORT_ALL_EXTERNAL RTL8366S_PORT_ALL_BUT_CPU + +#define RTL8366S_PORT_ALL_INTERNAL RTL8366S_PORT_CPU + +#define RTL8366S_VLAN_VID_MASK 0xfff +#define RTL8366S_VLAN_PRIORITY_SHIFT 12 +#define RTL8366S_VLAN_PRIORITY_MASK 0x7 +#define RTL8366S_VLAN_MEMBER_MASK 0x3f +#define RTL8366S_VLAN_UNTAG_SHIFT 6 +#define RTL8366S_VLAN_UNTAG_MASK 0x3f +#define RTL8366S_VLAN_FID_SHIFT 12 +#define RTL8366S_VLAN_FID_MASK 0x7 + +/* Green Ethernet Feature for PHY ports */ +#define RTL8366S_PHY_POWER_SAVING_CTRL_REG 0x000c +#define RTL8366S_PHY_POWER_SAVING_MASK 0x1000 + +#define RTL8366S_PHY_REG_MASK 0x001f +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK GENMASK(7, 5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK GENMASK(13, 9) + +#define RTL8366S_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8366S_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + + /* + * The following counters are accessible at a different + * base address. + */ + { 1, 0, 2, "Dot1dTpPortInDiscards" }, + { 1, 2, 2, "IfOutUcastPkts" }, + { 1, 4, 2, "IfOutMulticastPkts" }, + { 1, 6, 2, "IfOutBroadcastPkts" }, +}; + +static int rtl8366s_get_mib_counter(struct realtek_smi *smi, + int port, + struct rtl8366_mib_counter *mib, + u64 *mibvalue) +{ + u32 addr, val; + int ret; + int i; + + switch (mib->base) { + case 0: + addr = RTL8366S_MIB_COUNTER_BASE + + RTL8366S_MIB_COUNTER_PORT_OFFSET * port; + break; + case 1: + addr = RTL8366S_MIB_COUNTER_BASE2 + + RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; + break; + default: + return -EINVAL; + } + + addr += mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + ret = regmap_write(smi->map, addr, 0); + if (ret) + return ret; + + /* read MIB control register */ + ret = regmap_read(smi->map, RTL8366S_MIB_CTRL_REG, &val); + if (ret) + return -EIO; + + if (val & RTL8366S_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (val & RTL8366S_MIB_CTRL_RESET_MASK) + return -EIO; + + /* Read each individual MIB 16 bits at the time */ + *mibvalue = 0; + for (i = mib->length; i > 0; i--) { + ret = regmap_read(smi->map, addr + (i - 1), &val); + if (ret) + return ret; + *mibvalue = (*mibvalue << 16) | (val & 0xFFFF); + } + return 0; +} + +static int rtl8366s_phy_read(struct realtek_smi *smi, int phy, int regnum) +{ + u32 val; + u32 reg; + int ret; + + if (phy > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum; + + ret = regmap_write(smi->map, reg, 0); + if (ret) + return ret; + + ret = regmap_read(smi->map, RTL8366S_PHY_ACCESS_DATA_REG, &val); + if (ret) + return ret; + + return val; +} + +static int rtl8366s_phy_write(struct realtek_smi *smi, int phy, int regnum, + u16 val) +{ + u32 reg; + int ret; + + if (phy > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum; + + ret = regmap_write(smi->map, reg, val); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_reset_chip(struct realtek_smi *smi) +{ + int timeout = 10; + u32 val; + int ret; + + realtek_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, + RTL8366S_CHIP_CTRL_RESET_HW); + do { + usleep_range(20000, 25000); + ret = regmap_read(smi->map, RTL8366S_RESET_CTRL_REG, &val); + if (ret) + return ret; + + if (!(val & RTL8366S_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + dev_err(smi->dev, "timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static enum dsa_tag_protocol rtl8366s_get_tag_protocol(struct dsa_switch *ds, + int port, + enum dsa_tag_protocol mp) +{ + return DSA_TAG_PROTO_RTL8366S; +} + +static void +rtl8366s_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface, struct phy_device *phydev, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct realtek_smi *smi = ds->priv; + int ret; + + if (port != RTL8366S_PORT_NUM_CPU) + return; + + /* Force the fixed CPU port into 1Gbit mode, no autonegotiation */ + ret = regmap_update_bits(smi->map, RTL8366S_MAC_FORCE_CTRL1_REG, + BIT(port), BIT(port)); + if (ret) { + dev_err(smi->dev, "failed to force 1Gbit on CPU port\n"); + return; + } + + ret = regmap_update_bits(smi->map, RTL8366S_PAACR2, + 0xFF00U, + RTL8366S_PAACR_CPU_PORT << 8); + if (ret) { + dev_err(smi->dev, "failed to set PAACR on CPU port\n"); + return; + } + + /* Enable the CPU port */ + ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), + 0); + if (ret) { + dev_err(smi->dev, "failed to enable the CPU port\n"); + return; + } +} + +static void +rtl8366s_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface) +{ + struct realtek_smi *smi = ds->priv; + int ret; + + if (port != RTL8366S_PORT_NUM_CPU) + return; + + /* Disable the CPU port */ + ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), + BIT(port)); + if (ret) { + dev_err(smi->dev, "failed to disable the CPU port\n"); + return; + } +} + +static int rtl8366s_setup(struct dsa_switch *ds) +{ + struct realtek_smi *smi = ds->priv; + int ret; + + /* Reset chip */ + ret = rtl8366s_reset_chip(smi); + if (ret) + return ret; + + /* Set up the "green ethernet" feature */ + ret = regmap_update_bits(smi->map, RTL8366S_GREEN_ETHERNET_CTRL_REG, + RTL8366S_GREEN_ETHERNET_CTRL_MASK, + RTL8366S_GREEN_ETHERNET_TX | + RTL8366S_GREEN_ETHERNET_RX); + if (ret) + return ret; + + /* Enable CPU port with custom tag 8899 */ + ret = regmap_write(smi->map, RTL8366S_CPU_CTRL_REG, + RTL8366S_PORT_CPU); + if (ret) + return ret; + + /* Make sure we default-enable the fixed CPU port */ + ret = regmap_update_bits(smi->map, RTL8366S_PECR, + RTL8366S_PORT_CPU, 0); + if (ret) + return ret; + + /* Enable learning for all ports */ + ret = regmap_write(smi->map, RTL8366S_SSCR0, 0); + if (ret) + return ret; + + /* Enable auto ageing for all ports */ + ret = regmap_write(smi->map, RTL8366S_SSCR1, 0); + if (ret) + return ret; + + /* Don't drop packets whose DA has not been learned */ + ret = regmap_update_bits(smi->map, RTL8366S_SSCR2, + RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0); + if (ret) + return ret; + + /* Connect Port 4 PHY to RGMII + * TODO: Make it configurable in DTS + */ + ret = regmap_update_bits(smi->map, RTL8366S_PMC0, + RTL8366S_PMC0_P4_IOMODE_MASK, + RTL8366S_PMC0_P4_IOMODE_PHY_TO_RGMII); + if (ret) + return ret; + + /* Set up port-based VLAN */ + ret = rtl8366_init_vlan(smi); + if (ret) + return ret; + + /* Keep original tagged/untagged on egress */ + ret = regmap_update_bits(smi->map, + RTL8366S_EGRESS_KEEP_FORMAT_REG, + RTL8366S_EGRESS_KEEP_FORMAT_MASK, + RTL8366S_EGRESS_KEEP_FORMAT_ALL); + if (ret) + return ret; + + /* Enable Link Aggregation "Dump" mode. The switch will + * automatically set hash value mapping to LAG ports. + */ + ret = regmap_write(smi->map, RTL8366S_LAGCR, + RTL8366S_LAGCR_MODE_DUMP); + if (ret) + return ret; + + ret = realtek_smi_setup_mdio(smi); + if (ret) { + dev_info(smi->dev, "could not set up MDIO bus\n"); + return -ENODEV; + } + + ds->mtu_enforcement_ingress = true; + + return 0; +} + +static int rtl8366s_get_vlan_4k(struct realtek_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int ret; + int i; + + memset(vlan4k, 0, sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366S_NUM_VIDS) + return -EINVAL; + + /* write VID */ + ret = regmap_write(smi->map, RTL8366S_VLAN_TABLE_WRITE_BASE, + vid & RTL8366S_VLAN_VID_MASK); + if (ret) + return ret; + + /* write table access control word */ + ret = regmap_write(smi->map, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_READ_CTRL); + if (ret) + return ret; + + for (i = 0; i < 2; i++) { + ret = regmap_read(smi->map, + RTL8366S_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (ret) + return ret; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_4k(struct realtek_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int ret; + int i; + + if (vlan4k->vid >= RTL8366S_NUM_VIDS || + vlan4k->member > RTL8366S_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + ret = regmap_write(smi->map, + RTL8366S_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (ret) + return ret; + } + + /* write table access control word */ + ret = regmap_write(smi->map, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_WRITE_CTRL); + + return ret; +} + +static int rtl8366s_get_vlan_mc(struct realtek_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int ret; + int i; + + memset(vlanmc, 0, sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 2; i++) { + ret = regmap_read(smi->map, + RTL8366S_VLAN_MC_BASE(index) + i, + &data[i]); + if (ret) + return ret; + } + + vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) & + RTL8366S_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_mc(struct realtek_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int ret; + int i; + + if (index >= RTL8366S_NUM_VLANS || + vlanmc->vid >= RTL8366S_NUM_VIDS || + vlanmc->priority > RTL8366S_PRIORITYMAX || + vlanmc->member > RTL8366S_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) << + RTL8366S_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + ret = regmap_write(smi->map, + RTL8366S_VLAN_MC_BASE(index) + i, + data[i]); + if (ret) + return ret; + } + + return 0; +} + +static int rtl8366s_get_mc_index(struct realtek_smi *smi, int port, int *val) +{ + u32 data; + int ret; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + ret = regmap_read(smi->map, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (ret) + return ret; + + *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366S_PORT_VLAN_CTRL_MASK; + + return 0; +} + +static int rtl8366s_set_mc_index(struct realtek_smi *smi, int port, int index) +{ + if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + return regmap_update_bits(smi->map, RTL8366S_PORT_VLAN_CTRL_REG(port), + RTL8366S_PORT_VLAN_CTRL_MASK << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366S_PORT_VLAN_CTRL_MASK) << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366s_enable_vlan(struct realtek_smi *smi, bool enable) +{ + return regmap_update_bits(smi->map, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN, + enable ? RTL8366S_SGCR_EN_VLAN : 0); +} + +static int rtl8366s_enable_vlan4k(struct realtek_smi *smi, bool enable) +{ + return regmap_update_bits(smi->map, RTL8366S_VLAN_TB_CTRL_REG, + 1, enable); +} + +static bool rtl8366s_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan) +{ + unsigned int max = RTL8366S_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366S_NUM_VIDS - 1; + + return vlan && vlan < max; +} + +static int +rtl8366s_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct realtek_smi *smi = ds->priv; + + return regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), 0); +} + +static void +rtl8366s_port_disable(struct dsa_switch *ds, int port) +{ + struct realtek_smi *smi = ds->priv; + + regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), BIT(port)); +} + +static int +rtl8366s_port_bridge_join(struct dsa_switch *ds, int port, + struct net_device *bridge) +{ + struct realtek_smi *smi = ds->priv; + unsigned int port_mask = 0; + int i; + + for (i = 0; i < RTL8366S_NUM_PORTS; i++) { + unsigned int mask; + int ret; + + if (dsa_to_port(ds, i)->bridge_dev != bridge) + continue; + + /* Add this port to the portvlan mask of the other ports + * in the bridge + */ + mask = BIT(port); + mask |= mask << RTL8366S_VLAN_UNTAG_SHIFT; + ret = regmap_update_bits(smi->map, + RTL8366S_VLAN_MC_BASE(i) + 1, + mask, mask); + if (ret) + return ret; + + port_mask |= BIT(i); + } + + /* Add all other ports to this ports portvlan mask */ + port_mask |= port_mask << RTL8366S_VLAN_UNTAG_SHIFT; + return regmap_update_bits(smi->map, RTL8366S_VLAN_MC_BASE(port) + 1, + port_mask, port_mask); +} + +static void +rtl8366s_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *bridge) +{ + struct realtek_smi *smi = ds->priv; + unsigned int port_mask; + int i; + + for (i = 0; i < RTL8366S_NUM_PORTS; i++) { + unsigned int mask; + + if (dsa_to_port(ds, i)->bridge_dev != bridge) + continue; + + /* Remove this port from the portvlan mask of the other + * ports in the bridge + */ + mask = BIT(port); + mask |= mask << RTL8366S_VLAN_UNTAG_SHIFT; + regmap_update_bits(smi->map, + RTL8366S_VLAN_MC_BASE(i) + 1, + mask, 0); + } + + /* Set the cpu port to be the only one else in the portvlan mask + * of this port + */ + port_mask = BIT(port) | BIT(RTL8366S_PORT_NUM_CPU); + port_mask |= port_mask << RTL8366S_VLAN_UNTAG_SHIFT; + regmap_write(smi->map, RTL8366S_VLAN_MC_BASE(port) + 1, + port_mask); +} + +static void +rtl8366s_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct realtek_smi *smi = ds->priv; + enum RTL8366S_STP_STATE val; + + switch (state) { + case BR_STATE_DISABLED: + val = RTL8366S_STP_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val = RTL8366S_STP_BLOCKING; + break; + case BR_STATE_LEARNING: + val = RTL8366S_STP_LEARNING; + break; + case BR_STATE_FORWARDING: + default: + val = RTL8366S_STP_FORWARDING; + break; + } + + /* The HW supports 8 MSTIs but we only use 0 */ + regmap_update_bits(smi->map, RTL8366S_STP_REG(port), + RTL8366S_STP_MASK, val); +} + +static int rtl8366s_port_vlan_filtering(struct dsa_switch *ds, int port, + bool vlan_filtering) +{ + struct realtek_smi *smi = ds->priv; + unsigned int val; + int ret; + + /* Enable/Disable VLAN ingress filtering */ + val = BIT(port); + ret = regmap_update_bits(smi->map, RTL8366S_VLAN_MEMBERINGRESS_REG, + val, vlan_filtering ? val : 0); + if (ret) + return ret; + + /* Disable/Enable keep original tagged/untagged */ + val = FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, val); + ret = regmap_update_bits(smi->map, RTL8366S_EGRESS_KEEP_FORMAT_REG, + val, vlan_filtering ? 0 : val); + if (ret) + return ret; + + return rtl8366_vlan_filtering(ds, port, vlan_filtering); +} + +static int rtl8366s_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct realtek_smi *smi = ds->priv; + unsigned int val, dir; + int ret; + + /* The source and the monitor port cannot be the same */ + if (port == mirror->to_local_port) + return -EOPNOTSUPP; + + ret = regmap_read(smi->map, RTL8366S_PMCR, &val); + if (ret) + return ret; + + dir = ingress ? RTL8366S_PMCR_MIRROR_RX : RTL8366S_PMCR_MIRROR_TX; + /* RTL8366S only supports one port mirror set */ + if (val & dir) + return -EEXIST; + + /* If the other direction is active, allow setting up both + * directions for the same source and monitor ports + */ + if (val & (RTL8366S_PMCR_MIRROR_RX | RTL8366S_PMCR_MIRROR_TX)) { + int source, monitor; + + source = FIELD_GET(RTL8366S_PMCR_SOURCE_MASK, val); + monitor = FIELD_GET(RTL8366S_PMCR_MINITOR_MASK, val); + + if (source != port || monitor != mirror->to_local_port) + return -EEXIST; + } else { + val &= ~RTL8366S_PMCR_SOURCE_MASK; + val |= FIELD_PREP(RTL8366S_PMCR_SOURCE_MASK, port); + val &= ~RTL8366S_PMCR_MINITOR_MASK; + val |= FIELD_PREP(RTL8366S_PMCR_MINITOR_MASK, + mirror->to_local_port); + } + + val |= dir; + + return regmap_write(smi->map, RTL8366S_PMCR, val); +} + +static void rtl8366s_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct realtek_smi *smi = ds->priv; + unsigned int dir; + + dir = mirror->ingress ? RTL8366S_PMCR_MIRROR_RX : RTL8366S_PMCR_MIRROR_TX; + regmap_update_bits(smi->map, RTL8366S_PMCR, dir, 0); +} + +static int rtl8366s_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +{ + struct realtek_smi *smi = ds->priv; + u32 len; + + /* When a new MTU is set, DSA always set the CPU port's MTU to the + * largest MTU of the slave ports. Because the switch only has a global + * max length register, only allowing CPU port here is enough. + */ + if (port != RTL8366S_PORT_NUM_CPU) + return 0; + + /* Includes Ethernet header and FCS length. + * + * Note that the CPU tag does not count towards its length, the + * same reason why the frame must be padded _before_ inserting + * the CPU tag on xmit. + */ + new_mtu += ETH_HLEN + ETH_FCS_LEN; + if (new_mtu <= 1522) + len = RTL8366S_SGCR_MAX_LENGTH_1522; + else if (new_mtu <= 1536) + len = RTL8366S_SGCR_MAX_LENGTH_1536; + else if (new_mtu <= 1552) + len = RTL8366S_SGCR_MAX_LENGTH_1552; + else + len = RTL8366S_SGCR_MAX_LENGTH_16000; + + return regmap_update_bits(smi->map, RTL8366S_SGCR, + RTL8366S_SGCR_MAX_LENGTH_MASK, + len); +} + +static int rtl8366s_port_max_mtu(struct dsa_switch *ds, int port) +{ + return 16000 - ETH_HLEN - ETH_FCS_LEN; +} + +static int rtl8366s_port_lag_change(struct dsa_switch *ds, int port) +{ + const struct dsa_port *dp = dsa_to_port(ds, port); + struct realtek_smi *smi = ds->priv; + unsigned int val; + + val = FIELD_PREP(RTL8366S_LAGCR_PORTMAP_MASK, BIT(port)); + + return regmap_update_bits(smi->map, RTL8366S_LAGCR, val, + dp->lag_tx_enabled ? val : 0); +} + +static int rtl8366s_port_lag_join(struct dsa_switch *ds, int port, + struct net_device *lag, + struct netdev_lag_upper_info *info) +{ + struct realtek_smi *smi = ds->priv; + const struct dsa_port *dp; + unsigned int val; + int count = 0; + + /* Only supports hash type */ + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) + return -EOPNOTSUPP; + + list_for_each_entry(dp, dp->dst->ports, list) { + if (dp->lag_dev == lag) + count++; + /* Only supports 1 LAG set */ + else if (dp->lag_dev) + return -EBUSY; + } + + /* Only supports maximum LAG member of 4 */ + if (count >= 4) + return -ENOSPC; + + val = FIELD_PREP(RTL8366S_LAGCR_PORTMAP_MASK, BIT(port)); + + return regmap_update_bits(smi->map, RTL8366S_LAGCR, val, val); +} + +static int rtl8366s_port_lag_leave(struct dsa_switch *ds, int port, + struct net_device *lag) +{ + struct realtek_smi *smi = ds->priv; + unsigned int val; + + val = FIELD_PREP(RTL8366S_LAGCR_PORTMAP_MASK, BIT(port)); + + return regmap_update_bits(smi->map, RTL8366S_LAGCR, val, 0); +} + +static int rtl8366s_detect(struct realtek_smi *smi) +{ + struct device *dev = smi->dev; + unsigned int chip_ver; + unsigned int chip_id; + int ret; + + ret = regmap_read(smi->map, RTL8366S_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(dev, "unable to read chip id (%d)\n", ret); + return ret; + } + + switch (chip_id) { + case RTL8366S_CHIP_ID_8366: + break; + default: + dev_err(dev, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = regmap_read(smi->map, RTL8366S_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(dev, "unable to read chip version (%d)\n", ret); + return ret; + } + + chip_ver &= RTL8366S_CHIP_VERSION_MASK; + dev_info(dev, "RTL%04x ver. %u chip found\n", chip_id, chip_ver); + + smi->cpu_port = RTL8366S_PORT_NUM_CPU; + smi->num_ports = RTL8366S_NUM_PORTS; + smi->num_vlan_mc = RTL8366S_NUM_VLANS; + smi->mib_counters = rtl8366s_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters); + + return 0; +} + +static const struct dsa_switch_ops rtl8366s_switch_ops = { + .get_tag_protocol = rtl8366s_get_tag_protocol, + .setup = rtl8366s_setup, + .phylink_mac_link_down = rtl8366s_mac_link_down, + .phylink_mac_link_up = rtl8366s_mac_link_up, + .get_strings = rtl8366_get_strings, + .get_ethtool_stats = rtl8366_get_ethtool_stats, + .get_sset_count = rtl8366_get_sset_count, + .port_enable = rtl8366s_port_enable, + .port_disable = rtl8366s_port_disable, + .port_bridge_join = rtl8366s_port_bridge_join, + .port_bridge_leave = rtl8366s_port_bridge_leave, + .port_stp_state_set = rtl8366s_port_stp_state_set, + .port_vlan_filtering = rtl8366s_port_vlan_filtering, + .port_vlan_add = rtl8366_vlan_add, + .port_vlan_del = rtl8366_vlan_del, + .port_mirror_add = rtl8366s_port_mirror_add, + .port_mirror_del = rtl8366s_port_mirror_del, + .port_change_mtu = rtl8366s_port_change_mtu, + .port_max_mtu = rtl8366s_port_max_mtu, + .port_lag_change = rtl8366s_port_lag_change, + .port_lag_join = rtl8366s_port_lag_join, + .port_lag_leave = rtl8366s_port_lag_leave, +}; + +static const struct realtek_smi_ops rtl8366s_smi_ops = { + .detect = rtl8366s_detect, + .get_mib_counter = rtl8366s_get_mib_counter, + .get_vlan_mc = rtl8366s_get_vlan_mc, + .set_vlan_mc = rtl8366s_set_vlan_mc, + .get_vlan_4k = rtl8366s_get_vlan_4k, + .set_vlan_4k = rtl8366s_set_vlan_4k, + .get_mc_index = rtl8366s_get_mc_index, + .set_mc_index = rtl8366s_set_mc_index, + .is_vlan_valid = rtl8366s_is_vlan_valid, + .enable_vlan = rtl8366s_enable_vlan, + .enable_vlan4k = rtl8366s_enable_vlan4k, + .phy_read = rtl8366s_phy_read, + .phy_write = rtl8366s_phy_write, +}; + +static const struct realtek_smi_variant rtl8366s_variant = { + .ds_ops = &rtl8366s_switch_ops, + .ops = &rtl8366s_smi_ops, + .clk_delay = 10, + .cmd_read = 0xa9, + .cmd_write = 0xa8, +}; +EXPORT_SYMBOL_GPL(rtl8366s_variant); -- 2.25.1 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang @ 2021-02-17 7:37 ` kernel test robot 2021-02-17 9:57 ` kernel test robot ` (2 subsequent siblings) 3 siblings, 0 replies; 17+ messages in thread From: kernel test robot @ 2021-02-17 7:37 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 10322 bytes --] Hi DENG, [FYI, it's a private test report for your RFC patch.] [auto build test ERROR on net-next/master] url: https://github.com/0day-ci/linux/commits/DENG-Qingfang/DSA-driver-for-Realtek-RTL8366S-SR/20210217-143046 base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 06b334f08b4f0e53be64160392be4c37db28a413 config: parisc-randconfig-m031-20210216 (attached as .config) compiler: hppa-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/3cd6e7f27c49d9e06810a3ee0b03fbb6f20a40b9 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review DENG-Qingfang/DSA-driver-for-Realtek-RTL8366S-SR/20210217-143046 git checkout 3cd6e7f27c49d9e06810a3ee0b03fbb6f20a40b9 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=parisc If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): drivers/net/dsa/rtl8366s.c: In function 'rtl8366s_port_vlan_filtering': >> drivers/net/dsa/rtl8366s.c:928:9: error: too few arguments to function 'rtl8366_vlan_filtering' 928 | return rtl8366_vlan_filtering(ds, port, vlan_filtering); | ^~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/net/dsa/rtl8366s.c:14: drivers/net/dsa/realtek-smi-core.h:133:5: note: declared here 133 | int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, | ^~~~~~~~~~~~~~~~~~~~~~ In file included from include/linux/skbuff.h:13, from include/linux/if_ether.h:19, from include/linux/etherdevice.h:20, from drivers/net/dsa/rtl8366s.c:10: drivers/net/dsa/rtl8366s.c: In function 'rtl8366s_port_lag_join': >> include/linux/list.h:522:18: error: invalid type argument of '->' (have 'struct list_head') 522 | list_entry((ptr)->next, type, member) | ^~ include/linux/kernel.h:693:26: note: in definition of macro 'container_of' 693 | void *__mptr = (void *)(ptr); \ | ^~~ include/linux/list.h:522:2: note: in expansion of macro 'list_entry' 522 | list_entry((ptr)->next, type, member) | ^~~~~~~~~~ include/linux/list.h:628:13: note: in expansion of macro 'list_first_entry' 628 | for (pos = list_first_entry(head, typeof(*pos), member); \ | ^~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1049:2: note: in expansion of macro 'list_for_each_entry' 1049 | list_for_each_entry(dp, dp->dst->ports, list) { | ^~~~~~~~~~~~~~~~~~~ In file included from <command-line>: >> include/linux/list.h:522:18: error: invalid type argument of '->' (have 'struct list_head') 522 | list_entry((ptr)->next, type, member) | ^~ include/linux/compiler_types.h:300:9: note: in definition of macro '__compiletime_assert' 300 | if (!(condition)) \ | ^~~~~~~~~ include/linux/compiler_types.h:320:2: note: in expansion of macro '_compiletime_assert' 320 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) | ^~~~~~~~~~~~~~~~~~~ include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' 39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) | ^~~~~~~~~~~~~~~~~~ include/linux/kernel.h:694:2: note: in expansion of macro 'BUILD_BUG_ON_MSG' 694 | BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \ | ^~~~~~~~~~~~~~~~ include/linux/kernel.h:694:20: note: in expansion of macro '__same_type' 694 | BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \ | ^~~~~~~~~~~ include/linux/list.h:511:2: note: in expansion of macro 'container_of' 511 | container_of(ptr, type, member) | ^~~~~~~~~~~~ include/linux/list.h:522:2: note: in expansion of macro 'list_entry' 522 | list_entry((ptr)->next, type, member) | ^~~~~~~~~~ include/linux/list.h:628:13: note: in expansion of macro 'list_first_entry' 628 | for (pos = list_first_entry(head, typeof(*pos), member); \ | ^~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1049:2: note: in expansion of macro 'list_for_each_entry' 1049 | list_for_each_entry(dp, dp->dst->ports, list) { | ^~~~~~~~~~~~~~~~~~~ >> include/linux/list.h:522:18: error: invalid type argument of '->' (have 'struct list_head') 522 | list_entry((ptr)->next, type, member) | ^~ include/linux/compiler_types.h:300:9: note: in definition of macro '__compiletime_assert' 300 | if (!(condition)) \ | ^~~~~~~~~ include/linux/compiler_types.h:320:2: note: in expansion of macro '_compiletime_assert' 320 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) | ^~~~~~~~~~~~~~~~~~~ include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' 39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) | ^~~~~~~~~~~~~~~~~~ include/linux/kernel.h:694:2: note: in expansion of macro 'BUILD_BUG_ON_MSG' 694 | BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \ | ^~~~~~~~~~~~~~~~ include/linux/kernel.h:695:6: note: in expansion of macro '__same_type' 695 | !__same_type(*(ptr), void), \ | ^~~~~~~~~~~ include/linux/list.h:511:2: note: in expansion of macro 'container_of' 511 | container_of(ptr, type, member) | ^~~~~~~~~~~~ include/linux/list.h:522:2: note: in expansion of macro 'list_entry' 522 | list_entry((ptr)->next, type, member) | ^~~~~~~~~~ include/linux/list.h:628:13: note: in expansion of macro 'list_first_entry' 628 | for (pos = list_first_entry(head, typeof(*pos), member); \ | ^~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1049:2: note: in expansion of macro 'list_for_each_entry' 1049 | list_for_each_entry(dp, dp->dst->ports, list) { | ^~~~~~~~~~~~~~~~~~~ In file included from include/linux/preempt.h:11, from include/linux/spinlock.h:51, from include/linux/mmzone.h:8, from include/linux/gfp.h:6, from include/linux/mm.h:10, from include/linux/bvec.h:14, from include/linux/skbuff.h:17, from include/linux/if_ether.h:19, from include/linux/etherdevice.h:20, from drivers/net/dsa/rtl8366s.c:10: >> include/linux/list.h:619:16: error: invalid operands to binary == (have 'const struct list_head *' and 'struct list_head') 619 | (&pos->member == (head)) | ^~ ~~~~~~ include/linux/list.h:629:8: note: in expansion of macro 'list_entry_is_head' 629 | !list_entry_is_head(pos, head, member); \ | ^~~~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1049:2: note: in expansion of macro 'list_for_each_entry' 1049 | list_for_each_entry(dp, dp->dst->ports, list) { | ^~~~~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c: At top level: >> drivers/net/dsa/rtl8366s.c:1130:25: error: initialization of 'int (*)(struct dsa_switch *, int, bool, struct netlink_ext_ack *)' {aka 'int (*)(struct dsa_switch *, int, _Bool, struct netlink_ext_ack *)'} from incompatible pointer type 'int (*)(struct dsa_switch *, int, bool)' {aka 'int (*)(struct dsa_switch *, int, _Bool)'} [-Werror=incompatible-pointer-types] 1130 | .port_vlan_filtering = rtl8366s_port_vlan_filtering, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1130:25: note: (near initialization for 'rtl8366s_switch_ops.port_vlan_filtering') >> drivers/net/dsa/rtl8366s.c:1158:41: error: static declaration of 'rtl8366s_variant' follows non-static declaration 1158 | static const struct realtek_smi_variant rtl8366s_variant = { | ^~~~~~~~~~~~~~~~ In file included from drivers/net/dsa/rtl8366s.c:14: drivers/net/dsa/realtek-smi-core.h:146:41: note: previous declaration of 'rtl8366s_variant' was here 146 | extern const struct realtek_smi_variant rtl8366s_variant; | ^~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1158:41: warning: 'rtl8366s_variant' defined but not used [-Wunused-const-variable=] 1158 | static const struct realtek_smi_variant rtl8366s_variant = { | ^~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/rtl8366_vlan_filtering +928 drivers/net/dsa/rtl8366s.c 906 907 static int rtl8366s_port_vlan_filtering(struct dsa_switch *ds, int port, 908 bool vlan_filtering) 909 { 910 struct realtek_smi *smi = ds->priv; 911 unsigned int val; 912 int ret; 913 914 /* Enable/Disable VLAN ingress filtering */ 915 val = BIT(port); 916 ret = regmap_update_bits(smi->map, RTL8366S_VLAN_MEMBERINGRESS_REG, 917 val, vlan_filtering ? val : 0); 918 if (ret) 919 return ret; 920 921 /* Disable/Enable keep original tagged/untagged */ 922 val = FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, val); 923 ret = regmap_update_bits(smi->map, RTL8366S_EGRESS_KEEP_FORMAT_REG, 924 val, vlan_filtering ? 0 : val); 925 if (ret) 926 return ret; 927 > 928 return rtl8366_vlan_filtering(ds, port, vlan_filtering); 929 } 930 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 30527 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang 2021-02-17 7:37 ` kernel test robot @ 2021-02-17 9:57 ` kernel test robot 2021-02-17 11:12 ` Linus Walleij 2021-02-17 12:25 ` Vladimir Oltean 3 siblings, 0 replies; 17+ messages in thread From: kernel test robot @ 2021-02-17 9:57 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 13448 bytes --] Hi DENG, [FYI, it's a private test report for your RFC patch.] [auto build test ERROR on net-next/master] url: https://github.com/0day-ci/linux/commits/DENG-Qingfang/DSA-driver-for-Realtek-RTL8366S-SR/20210217-143046 base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 06b334f08b4f0e53be64160392be4c37db28a413 config: riscv-randconfig-r014-20210216 (attached as .config) compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project c9439ca36342fb6013187d0a69aef92736951476) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install riscv cross compiling tool for clang build # apt-get install binutils-riscv64-linux-gnu # https://github.com/0day-ci/linux/commit/3cd6e7f27c49d9e06810a3ee0b03fbb6f20a40b9 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review DENG-Qingfang/DSA-driver-for-Realtek-RTL8366S-SR/20210217-143046 git checkout 3cd6e7f27c49d9e06810a3ee0b03fbb6f20a40b9 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): >> drivers/net/dsa/rtl8366s.c:928:56: error: too few arguments to function call, expected 4, have 3 return rtl8366_vlan_filtering(ds, port, vlan_filtering); ~~~~~~~~~~~~~~~~~~~~~~ ^ drivers/net/dsa/realtek-smi-core.h:133:5: note: 'rtl8366_vlan_filtering' declared here int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, ^ >> drivers/net/dsa/rtl8366s.c:1049:2: error: member reference type 'struct list_head' is not a pointer; did you mean to use '.'? list_for_each_entry(dp, dp->dst->ports, list) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:628:13: note: expanded from macro 'list_for_each_entry' for (pos = list_first_entry(head, typeof(*pos), member); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:522:18: note: expanded from macro 'list_first_entry' list_entry((ptr)->next, type, member) ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:511:15: note: expanded from macro 'list_entry' container_of(ptr, type, member) ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ include/linux/kernel.h:693:26: note: expanded from macro 'container_of' void *__mptr = (void *)(ptr); \ ^~~ >> drivers/net/dsa/rtl8366s.c:1049:2: error: member reference type 'struct list_head' is not a pointer; did you mean to use '.'? list_for_each_entry(dp, dp->dst->ports, list) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:628:13: note: expanded from macro 'list_for_each_entry' for (pos = list_first_entry(head, typeof(*pos), member); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:522:18: note: expanded from macro 'list_first_entry' list_entry((ptr)->next, type, member) ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:511:15: note: expanded from macro 'list_entry' container_of(ptr, type, member) ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) include/linux/compiler_types.h:320:22: note: expanded from macro 'compiletime_assert' _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/compiler_types.h:308:23: note: expanded from macro '_compiletime_assert' __compiletime_assert(condition, msg, prefix, suffix) ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/compiler_types.h:300:9: note: expanded from macro '__compiletime_assert' if (!(condition)) \ ^~~~~~~~~ >> drivers/net/dsa/rtl8366s.c:1049:2: error: member reference type 'struct list_head' is not a pointer; did you mean to use '.'? list_for_each_entry(dp, dp->dst->ports, list) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:628:13: note: expanded from macro 'list_for_each_entry' for (pos = list_first_entry(head, typeof(*pos), member); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:522:18: note: expanded from macro 'list_first_entry' list_entry((ptr)->next, type, member) ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:511:15: note: expanded from macro 'list_entry' container_of(ptr, type, member) ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all) include/linux/compiler_types.h:320:22: note: expanded from macro 'compiletime_assert' _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/compiler_types.h:308:23: note: expanded from macro '_compiletime_assert' __compiletime_assert(condition, msg, prefix, suffix) ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/compiler_types.h:300:9: note: expanded from macro '__compiletime_assert' if (!(condition)) \ ^~~~~~~~~ >> drivers/net/dsa/rtl8366s.c:1049:2: error: invalid operands to binary expression ('const struct list_head *' and 'struct list_head') list_for_each_entry(dp, dp->dst->ports, list) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:629:8: note: expanded from macro 'list_for_each_entry' !list_entry_is_head(pos, head, member); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/list.h:619:16: note: expanded from macro 'list_entry_is_head' (&pos->member == (head)) ~~~~~~~~~~~~ ^ ~~~~~~ >> drivers/net/dsa/rtl8366s.c:1130:25: error: incompatible function pointer types initializing 'int (*)(struct dsa_switch *, int, bool, struct netlink_ext_ack *)' (aka 'int (*)(struct dsa_switch *, int, _Bool, struct netlink_ext_ack *)') with an expression of type 'int (struct dsa_switch *, int, bool)' (aka 'int (struct dsa_switch *, int, _Bool)') [-Werror,-Wincompatible-function-pointer-types] .port_vlan_filtering = rtl8366s_port_vlan_filtering, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/dsa/rtl8366s.c:1158:41: error: static declaration of 'rtl8366s_variant' follows non-static declaration static const struct realtek_smi_variant rtl8366s_variant = { ^ drivers/net/dsa/realtek-smi-core.h:146:41: note: previous declaration is here extern const struct realtek_smi_variant rtl8366s_variant; ^ 7 errors generated. vim +928 drivers/net/dsa/rtl8366s.c 906 907 static int rtl8366s_port_vlan_filtering(struct dsa_switch *ds, int port, 908 bool vlan_filtering) 909 { 910 struct realtek_smi *smi = ds->priv; 911 unsigned int val; 912 int ret; 913 914 /* Enable/Disable VLAN ingress filtering */ 915 val = BIT(port); 916 ret = regmap_update_bits(smi->map, RTL8366S_VLAN_MEMBERINGRESS_REG, 917 val, vlan_filtering ? val : 0); 918 if (ret) 919 return ret; 920 921 /* Disable/Enable keep original tagged/untagged */ 922 val = FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, val); 923 ret = regmap_update_bits(smi->map, RTL8366S_EGRESS_KEEP_FORMAT_REG, 924 val, vlan_filtering ? 0 : val); 925 if (ret) 926 return ret; 927 > 928 return rtl8366_vlan_filtering(ds, port, vlan_filtering); 929 } 930 931 static int rtl8366s_port_mirror_add(struct dsa_switch *ds, int port, 932 struct dsa_mall_mirror_tc_entry *mirror, 933 bool ingress) 934 { 935 struct realtek_smi *smi = ds->priv; 936 unsigned int val, dir; 937 int ret; 938 939 /* The source and the monitor port cannot be the same */ 940 if (port == mirror->to_local_port) 941 return -EOPNOTSUPP; 942 943 ret = regmap_read(smi->map, RTL8366S_PMCR, &val); 944 if (ret) 945 return ret; 946 947 dir = ingress ? RTL8366S_PMCR_MIRROR_RX : RTL8366S_PMCR_MIRROR_TX; 948 /* RTL8366S only supports one port mirror set */ 949 if (val & dir) 950 return -EEXIST; 951 952 /* If the other direction is active, allow setting up both 953 * directions for the same source and monitor ports 954 */ 955 if (val & (RTL8366S_PMCR_MIRROR_RX | RTL8366S_PMCR_MIRROR_TX)) { 956 int source, monitor; 957 958 source = FIELD_GET(RTL8366S_PMCR_SOURCE_MASK, val); 959 monitor = FIELD_GET(RTL8366S_PMCR_MINITOR_MASK, val); 960 961 if (source != port || monitor != mirror->to_local_port) 962 return -EEXIST; 963 } else { 964 val &= ~RTL8366S_PMCR_SOURCE_MASK; 965 val |= FIELD_PREP(RTL8366S_PMCR_SOURCE_MASK, port); 966 val &= ~RTL8366S_PMCR_MINITOR_MASK; 967 val |= FIELD_PREP(RTL8366S_PMCR_MINITOR_MASK, 968 mirror->to_local_port); 969 } 970 971 val |= dir; 972 973 return regmap_write(smi->map, RTL8366S_PMCR, val); 974 } 975 976 static void rtl8366s_port_mirror_del(struct dsa_switch *ds, int port, 977 struct dsa_mall_mirror_tc_entry *mirror) 978 { 979 struct realtek_smi *smi = ds->priv; 980 unsigned int dir; 981 982 dir = mirror->ingress ? RTL8366S_PMCR_MIRROR_RX : RTL8366S_PMCR_MIRROR_TX; 983 regmap_update_bits(smi->map, RTL8366S_PMCR, dir, 0); 984 } 985 986 static int rtl8366s_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) 987 { 988 struct realtek_smi *smi = ds->priv; 989 u32 len; 990 991 /* When a new MTU is set, DSA always set the CPU port's MTU to the 992 * largest MTU of the slave ports. Because the switch only has a global 993 * max length register, only allowing CPU port here is enough. 994 */ 995 if (port != RTL8366S_PORT_NUM_CPU) 996 return 0; 997 998 /* Includes Ethernet header and FCS length. 999 * 1000 * Note that the CPU tag does not count towards its length, the 1001 * same reason why the frame must be padded _before_ inserting 1002 * the CPU tag on xmit. 1003 */ 1004 new_mtu += ETH_HLEN + ETH_FCS_LEN; 1005 if (new_mtu <= 1522) 1006 len = RTL8366S_SGCR_MAX_LENGTH_1522; 1007 else if (new_mtu <= 1536) 1008 len = RTL8366S_SGCR_MAX_LENGTH_1536; 1009 else if (new_mtu <= 1552) 1010 len = RTL8366S_SGCR_MAX_LENGTH_1552; 1011 else 1012 len = RTL8366S_SGCR_MAX_LENGTH_16000; 1013 1014 return regmap_update_bits(smi->map, RTL8366S_SGCR, 1015 RTL8366S_SGCR_MAX_LENGTH_MASK, 1016 len); 1017 } 1018 1019 static int rtl8366s_port_max_mtu(struct dsa_switch *ds, int port) 1020 { 1021 return 16000 - ETH_HLEN - ETH_FCS_LEN; 1022 } 1023 1024 static int rtl8366s_port_lag_change(struct dsa_switch *ds, int port) 1025 { 1026 const struct dsa_port *dp = dsa_to_port(ds, port); 1027 struct realtek_smi *smi = ds->priv; 1028 unsigned int val; 1029 1030 val = FIELD_PREP(RTL8366S_LAGCR_PORTMAP_MASK, BIT(port)); 1031 1032 return regmap_update_bits(smi->map, RTL8366S_LAGCR, val, 1033 dp->lag_tx_enabled ? val : 0); 1034 } 1035 1036 static int rtl8366s_port_lag_join(struct dsa_switch *ds, int port, 1037 struct net_device *lag, 1038 struct netdev_lag_upper_info *info) 1039 { 1040 struct realtek_smi *smi = ds->priv; 1041 const struct dsa_port *dp; 1042 unsigned int val; 1043 int count = 0; 1044 1045 /* Only supports hash type */ 1046 if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) 1047 return -EOPNOTSUPP; 1048 > 1049 list_for_each_entry(dp, dp->dst->ports, list) { 1050 if (dp->lag_dev == lag) 1051 count++; 1052 /* Only supports 1 LAG set */ 1053 else if (dp->lag_dev) 1054 return -EBUSY; 1055 } 1056 1057 /* Only supports maximum LAG member of 4 */ 1058 if (count >= 4) 1059 return -ENOSPC; 1060 1061 val = FIELD_PREP(RTL8366S_LAGCR_PORTMAP_MASK, BIT(port)); 1062 1063 return regmap_update_bits(smi->map, RTL8366S_LAGCR, val, val); 1064 } 1065 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 44328 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang 2021-02-17 7:37 ` kernel test robot 2021-02-17 9:57 ` kernel test robot @ 2021-02-17 11:12 ` Linus Walleij 2021-02-17 12:45 ` DENG Qingfang 2021-02-17 12:25 ` Vladimir Oltean 3 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2021-02-17 11:12 UTC (permalink / raw) To: DENG Qingfang Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg Hi Qingfang, thanks for your patch! Overall it looks good and I will not nitpick details since this is RFC. On Wed, Feb 17, 2021 at 7:21 AM DENG Qingfang <dqfext@gmail.com> wrote: > > Support Realtek RTL8366S/SR switch > > Signed-off-by: DENG Qingfang <dqfext@gmail.com> I would mention that the DT bindings for the switch are already in Documentation/devicetree/bindings/net/dsa/realtek-smi.txt (Hmmm we should convert these bindings to YAML too.) > select NET_DSA_TAG_RTL4_A > + select NET_DSA_TAG_RTL8366S Hopefully we can use NET_DSA_TAG_RTL4_A for this switch as mentioned. > +/* bits 0..7 = port 0, bits 8..15 = port 1 */ > +#define RTL8366S_PAACR0 0x0011 > +/* bits 0..7 = port 2, bits 8..15 = port 3 */ > +#define RTL8366S_PAACR1 0x0012 > +/* bits 0..7 = port 4, bits 8..15 = port 5 */ > +#define RTL8366S_PAACR2 0x0013 Is this all? I was under the impression that RTL8366S supports up to 8 ports (7+1). > +#define RTL8366S_CHIP_ID_REG 0x0105 > +#define RTL8366S_CHIP_ID_8366 0x8366 Curiously RTL8366RB presents ID 0x5937. Oh well. Interesting engineering process I suppose. > +/* LED control registers */ > +#define RTL8366S_LED_BLINKRATE_REG 0x0420 > +#define RTL8366S_LED_BLINKRATE_BIT 0 > +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 > + > +#define RTL8366S_LED_CTRL_REG 0x0421 > +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 > +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 Again I wonder if there are more registers here for 8 ports? > +/* PHY registers control */ > +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 > +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 > + > +#define RTL8366S_PHY_CTRL_READ 1 > +#define RTL8366S_PHY_CTRL_WRITE 0 > + > +#define RTL8366S_PORT_NUM_CPU 5 > +#define RTL8366S_NUM_PORTS 6 Hm 5+1? Isn't RTL8366S 7+1? > +#define RTL8366S_PORT_1 BIT(0) /* In userspace port 0 */ > +#define RTL8366S_PORT_2 BIT(1) /* In userspace port 1 */ > +#define RTL8366S_PORT_3 BIT(2) /* In userspace port 2 */ > +#define RTL8366S_PORT_4 BIT(3) /* In userspace port 3 */ > +#define RTL8366S_PORT_5 BIT(4) /* In userspace port 4 */ > +#define RTL8366S_PORT_CPU BIT(5) /* CPU port */ Same here. Overall the question about whether the switch is 5+1 or 7+1 is my big design remark. Maybe it is only 5+1 who knows... Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 11:12 ` Linus Walleij @ 2021-02-17 12:45 ` DENG Qingfang 0 siblings, 0 replies; 17+ messages in thread From: DENG Qingfang @ 2021-02-17 12:45 UTC (permalink / raw) To: Linus Walleij Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 7:12 PM Linus Walleij <linus.walleij@linaro.org> wrote: > > Overall the question about whether the switch is 5+1 or 7+1 is my > big design remark. > > Maybe it is only 5+1 who knows... Yes, it's 5+1. https://cdn.jsdelivr.net/gh/libc0607/Realtek_switch_hacking@files/rtl8366s_8366sr_datasheet_vpre-1.4_20071022.pdf > > Yours, > Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang ` (2 preceding siblings ...) 2021-02-17 11:12 ` Linus Walleij @ 2021-02-17 12:25 ` Vladimir Oltean 2021-02-17 15:44 ` Linus Walleij 3 siblings, 1 reply; 17+ messages in thread From: Vladimir Oltean @ 2021-02-17 12:25 UTC (permalink / raw) To: DENG Qingfang Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, David S. Miller, Jakub Kicinski, netdev, Linus Walleij, Mauri Sandberg On Wed, Feb 17, 2021 at 02:21:39PM +0800, DENG Qingfang wrote: > Support Realtek RTL8366S/SR switch > > Signed-off-by: DENG Qingfang <dqfext@gmail.com> > --- > drivers/net/dsa/Kconfig | 1 + > drivers/net/dsa/Makefile | 2 +- > drivers/net/dsa/realtek-smi-core.c | 3 +- > drivers/net/dsa/realtek-smi-core.h | 1 + > drivers/net/dsa/rtl8366s.c | 1165 ++++++++++++++++++++++++++++ > 5 files changed, 1169 insertions(+), 3 deletions(-) > create mode 100644 drivers/net/dsa/rtl8366s.c > > diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig > index 3af373e90806..52f1df6ef53a 100644 > --- a/drivers/net/dsa/Kconfig > +++ b/drivers/net/dsa/Kconfig > @@ -75,6 +75,7 @@ config NET_DSA_REALTEK_SMI > tristate "Realtek SMI Ethernet switch family support" > depends on NET_DSA > select NET_DSA_TAG_RTL4_A > + select NET_DSA_TAG_RTL8366S > select FIXED_PHY > select IRQ_DOMAIN > select REALTEK_PHY > diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile > index f3598c040994..8c51c25d8378 100644 > --- a/drivers/net/dsa/Makefile > +++ b/drivers/net/dsa/Makefile > @@ -10,7 +10,7 @@ obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o > obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o > obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o > obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o > -realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o > +realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o rtl8366s.o > obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o > obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o > obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o > diff --git a/drivers/net/dsa/realtek-smi-core.c b/drivers/net/dsa/realtek-smi-core.c > index 8e49d4f85d48..e0ced416c362 100644 > --- a/drivers/net/dsa/realtek-smi-core.c > +++ b/drivers/net/dsa/realtek-smi-core.c > @@ -480,9 +480,8 @@ static const struct of_device_id realtek_smi_of_match[] = { > .data = &rtl8366rb_variant, > }, > { > - /* FIXME: add support for RTL8366S and more */ > .compatible = "realtek,rtl8366s", > - .data = NULL, > + .data = &rtl8366s_variant, > }, > { /* sentinel */ }, > }; > diff --git a/drivers/net/dsa/realtek-smi-core.h b/drivers/net/dsa/realtek-smi-core.h > index fcf465f7f922..a5d45b6f6de3 100644 > --- a/drivers/net/dsa/realtek-smi-core.h > +++ b/drivers/net/dsa/realtek-smi-core.h > @@ -143,5 +143,6 @@ int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset); > void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); > > extern const struct realtek_smi_variant rtl8366rb_variant; > +extern const struct realtek_smi_variant rtl8366s_variant; > > #endif /* _REALTEK_SMI_H */ > diff --git a/drivers/net/dsa/rtl8366s.c b/drivers/net/dsa/rtl8366s.c > new file mode 100644 > index 000000000000..718e492f8bbd > --- /dev/null > +++ b/drivers/net/dsa/rtl8366s.c > @@ -0,0 +1,1165 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Realtek SMI subdriver for the Realtek RTL8366S ethernet switch > + * > + * Copyright (C) 2021 DENG, Qingfang <dqfext@gmail.com> > + * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> > + * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> > + */ > + > +#include <linux/bitfield.h> > +#include <linux/etherdevice.h> > +#include <linux/if_bridge.h> > +#include <linux/regmap.h> > + > +#include "realtek-smi-core.h" > + > +#define RTL8366S_PHY_NO_MAX 4 > +#define RTL8366S_PHY_PAGE_MAX 7 > +#define RTL8366S_PHY_ADDR_MAX 31 > + > +/* Switch Global Configuration register */ > +#define RTL8366S_SGCR 0x0000 > +#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) > +#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) > +#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) > +#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) > +#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) > +#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) > +#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) > +#define RTL8366S_SGCR_EN_VLAN BIT(13) > + > +/* Port Enable Control register */ > +#define RTL8366S_PECR 0x0001 > + > +/* Switch Security Control registers */ > +#define RTL8366S_SSCR0 0x0002 > +#define RTL8366S_SSCR1 0x0003 > +#define RTL8366S_SSCR2 0x0004 > +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) > + > +/* Port Mode Control registers */ > +#define RTL8366S_PMC0 0x0005 > +#define RTL8366S_PMC0_SPI BIT(0) > +#define RTL8366S_PMC0_EN_AUTOLOAD BIT(1) > +#define RTL8366S_PMC0_PROBE BIT(2) > +#define RTL8366S_PMC0_DIS_BISR BIT(3) > +#define RTL8366S_PMC0_ADCTEST BIT(4) > +#define RTL8366S_PMC0_SRAM_DIAG BIT(5) > +#define RTL8366S_PMC0_EN_SCAN BIT(6) > +#define RTL8366S_PMC0_P4_IOMODE_MASK GENMASK(9, 7) > +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_GMAC \ > + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 0) > +#define RTL8366S_PMC0_P4_IOMODE_GMAC_TO_RGMII \ > + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 1) > +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_RGMII \ > + FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 2) > +#define RTL8366S_PMC0_P5_IOMODE_MASK GENMASK(12, 10) > +#define RTL8366S_PMC0_SDSMODE_MASK GENMASK(15, 13) > +#define RTL8366S_PMC1 0x0006 > + > +/* Port Mirror Control Register */ > +#define RTL8366S_PMCR 0x0007 > +#define RTL8366S_PMCR_SOURCE_MASK GENMASK(3, 0) > +#define RTL8366S_PMCR_MINITOR_MASK GENMASK(7, 4) > +#define RTL8366S_PMCR_MIRROR_RX BIT(8) > +#define RTL8366S_PMCR_MIRROR_TX BIT(9) > +#define RTL8366S_PMCR_MIRROR_SPC BIT(10) > +#define RTL8366S_PMCR_MIRROR_ISO BIT(11) > + > +/* Keep format on egress */ > +#define RTL8366S_EGRESS_KEEP_FORMAT_REG 0x0008 > +#define RTL8366S_EGRESS_KEEP_FORMAT_MASK GENMASK(15, 8) > +#define RTL8366S_EGRESS_KEEP_FORMAT_ALL \ > + FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, RTL8366S_PORT_ALL) > + > +/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */ > +#define RTL8366S_GREEN_ETHERNET_CTRL_REG 0x000a > +#define RTL8366S_GREEN_ETHERNET_CTRL_MASK 0x0018 > +#define RTL8366S_GREEN_ETHERNET_TX BIT(3) > +#define RTL8366S_GREEN_ETHERNET_RX BIT(4) > + > +/* bits 0..7 = port 0, bits 8..15 = port 1 */ > +#define RTL8366S_PAACR0 0x0011 > +/* bits 0..7 = port 2, bits 8..15 = port 3 */ > +#define RTL8366S_PAACR1 0x0012 > +/* bits 0..7 = port 4, bits 8..15 = port 5 */ > +#define RTL8366S_PAACR2 0x0013 > +#define RTL8366S_PAACR_SPEED_10M 0 > +#define RTL8366S_PAACR_SPEED_100M 1 > +#define RTL8366S_PAACR_SPEED_1000M 2 > +#define RTL8366S_PAACR_FULL_DUPLEX BIT(2) > +#define RTL8366S_PAACR_LINK_UP BIT(4) > +#define RTL8366S_PAACR_TX_PAUSE BIT(5) > +#define RTL8366S_PAACR_RX_PAUSE BIT(6) > +#define RTL8366S_PAACR_AN BIT(7) > + > +#define RTL8366S_PAACR_CPU_PORT (RTL8366S_PAACR_SPEED_1000M | \ > + RTL8366S_PAACR_FULL_DUPLEX | \ > + RTL8366S_PAACR_LINK_UP | \ > + RTL8366S_PAACR_TX_PAUSE | \ > + RTL8366S_PAACR_RX_PAUSE) > + > +/* Spanning Tree Protocol register */ > +#define RTL8366S_STP_BASE 0x003a > +#define RTL8366S_STP_REG(_p) \ > + (RTL8366S_STP_BASE + (_p)) > +#define RTL8366S_STP_MASK GENMASK(1, 0) > + > +enum RTL8366S_STP_STATE > +{ > + RTL8366S_STP_DISABLED = 0, > + RTL8366S_STP_BLOCKING, > + RTL8366S_STP_LEARNING, > + RTL8366S_STP_FORWARDING, > +}; > + > +#define RTL8366S_CPU_CTRL_REG 0x004f > +#define RTL8366S_CPU_DROP_UNKNOWN_DA BIT(14) > +#define RTL8366S_CPU_NO_TAG BIT(15) > + > +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 > +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ > + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) > +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf > +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) > + > +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 > +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 > +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 > +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 > +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 > +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 > +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 > + > +#define RTL8366S_RESET_CTRL_REG 0x0100 > +#define RTL8366S_CHIP_CTRL_RESET_HW BIT(0) > +#define RTL8366S_CHIP_CTRL_RESET_SW BIT(1) > + > +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 > +#define RTL8366S_CHIP_VERSION_MASK 0xf > +#define RTL8366S_CHIP_ID_REG 0x0105 > +#define RTL8366S_CHIP_ID_8366 0x8366 > + > +/* VLAN 4K access registers */ > +#define RTL8366S_VLAN_TB_CTRL_REG 0x010f > + > +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 > +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 > +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 > + > +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B > +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 > + > +/* VLAN filtering registers */ > +#define RTL8366S_VLAN_TAGINGRESS_REG 0x0378 > +#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 > + > +/* Link aggregation registers */ > +#define RTL8366S_LAGCR 0x0380 > +#define RTL8366S_LAGCR_MODE_DUMP BIT(0) > +#define RTL8366S_LAGCR_HASHSEL_MASK GENMASK(2, 1) > +#define RTL8366S_LAGCR_HASHSEL_DA_SA \ > + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 0) > +#define RTL8366S_LAGCR_HASHSEL_DA \ > + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 1) > +#define RTL8366S_LAGCR_HASHSEL_SA \ > + FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 2) > +#define RTL8366S_LAGCR_PORTMAP_MASK GENMASK(8, 3) > + > +#define RTL8366S_LAG_MAPPING_BASE 0x0381 > +#define RTL8366S_LAG_MAPPING_BIT 3 > +#define RTL8366S_LAG_MAPPING_MASK GENMASK(2, 0) > + > +#define RTL8366S_LAG_FC_CTRL_REG 0x0383 > +#define RTL8366S_LAG_FC_MASK GENMASK(5, 0) > + > +#define RTL8366S_LAG_QEMPTY_REG 0x0384 > +#define RTL8366S_LAG_QEMPTY_MASK GENMASK(5, 0) > + > +/* RMA register address */ > +#define RTL8366S_RMA_CONTROL_REG 0x0391 > +#define RTL8366S_RMA_IGMP BIT(10) > +#define RTL8366S_RMA_MLD BIT(11) > +#define RTL8366S_RMA_USER_DEFINED_BASE 0x0392 > + > +/* LED control registers */ > +#define RTL8366S_LED_BLINKRATE_REG 0x0420 > +#define RTL8366S_LED_BLINKRATE_BIT 0 > +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 > + > +#define RTL8366S_LED_CTRL_REG 0x0421 > +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 > +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 > + > +#define RTL8366S_MIB_COUNT 33 > +#define RTL8366S_GLOBAL_MIB_COUNT 1 > +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 > +#define RTL8366S_MIB_COUNTER_BASE 0x1000 > +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 > +#define RTL8366S_MIB_COUNTER_BASE2 0x1180 > +#define RTL8366S_MIB_CTRL_REG 0x11F0 > +#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF > +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 > +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 > + > +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 > +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 > +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC > + > + > +#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) > + > +#define RTL8366S_MAC_FORCE_CTRL0_REG 0x0F04 > +#define RTL8366S_MAC_FORCE_CTRL1_REG 0x0F05 > + > +/* PHY registers control */ > +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 > +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 > + > +#define RTL8366S_PHY_CTRL_READ 1 > +#define RTL8366S_PHY_CTRL_WRITE 0 > + > +#define RTL8366S_PORT_NUM_CPU 5 > +#define RTL8366S_NUM_PORTS 6 > +#define RTL8366S_NUM_VLANS 16 > +#define RTL8366S_NUM_LEDGROUPS 4 > +#define RTL8366S_NUM_VIDS 4096 > +#define RTL8366S_PRIORITYMAX 7 > +#define RTL8366S_FIDMAX 7 > + > + > +#define RTL8366S_PORT_1 BIT(0) /* In userspace port 0 */ > +#define RTL8366S_PORT_2 BIT(1) /* In userspace port 1 */ > +#define RTL8366S_PORT_3 BIT(2) /* In userspace port 2 */ > +#define RTL8366S_PORT_4 BIT(3) /* In userspace port 3 */ > +#define RTL8366S_PORT_5 BIT(4) /* In userspace port 4 */ > +#define RTL8366S_PORT_CPU BIT(5) /* CPU port */ > + > +#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ > + RTL8366S_PORT_2 | \ > + RTL8366S_PORT_3 | \ > + RTL8366S_PORT_4 | \ > + RTL8366S_PORT_5 | \ > + RTL8366S_PORT_CPU) > + > +#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ > + RTL8366S_PORT_2 | \ > + RTL8366S_PORT_3 | \ > + RTL8366S_PORT_4 | \ > + RTL8366S_PORT_5) > + > +#define RTL8366S_PORT_ALL_EXTERNAL RTL8366S_PORT_ALL_BUT_CPU > + > +#define RTL8366S_PORT_ALL_INTERNAL RTL8366S_PORT_CPU > + > +#define RTL8366S_VLAN_VID_MASK 0xfff > +#define RTL8366S_VLAN_PRIORITY_SHIFT 12 > +#define RTL8366S_VLAN_PRIORITY_MASK 0x7 > +#define RTL8366S_VLAN_MEMBER_MASK 0x3f > +#define RTL8366S_VLAN_UNTAG_SHIFT 6 > +#define RTL8366S_VLAN_UNTAG_MASK 0x3f > +#define RTL8366S_VLAN_FID_SHIFT 12 > +#define RTL8366S_VLAN_FID_MASK 0x7 > + > +/* Green Ethernet Feature for PHY ports */ > +#define RTL8366S_PHY_POWER_SAVING_CTRL_REG 0x000c > +#define RTL8366S_PHY_POWER_SAVING_MASK 0x1000 > + > +#define RTL8366S_PHY_REG_MASK 0x001f > +#define RTL8366S_PHY_PAGE_OFFSET 5 > +#define RTL8366S_PHY_PAGE_MASK GENMASK(7, 5) > +#define RTL8366S_PHY_NO_OFFSET 9 > +#define RTL8366S_PHY_NO_MASK GENMASK(13, 9) > + > +#define RTL8366S_MIB_RXB_ID 0 /* IfInOctets */ > +#define RTL8366S_MIB_TXB_ID 20 /* IfOutOctets */ I'm not going to do a detailed review on a driver that is a 90% copy of rtl8366rb. You should probably spend some time to avoid duplicating what is common. > + > +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { > + { 0, 0, 4, "IfInOctets" }, > + { 0, 4, 4, "EtherStatsOctets" }, > + { 0, 8, 2, "EtherStatsUnderSizePkts" }, > + { 0, 10, 2, "EtherFragments" }, > + { 0, 12, 2, "EtherStatsPkts64Octets" }, > + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, > + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, > + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, > + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, > + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, > + { 0, 24, 2, "EtherOversizeStats" }, > + { 0, 26, 2, "EtherStatsJabbers" }, > + { 0, 28, 2, "IfInUcastPkts" }, > + { 0, 30, 2, "EtherStatsMulticastPkts" }, > + { 0, 32, 2, "EtherStatsBroadcastPkts" }, > + { 0, 34, 2, "EtherStatsDropEvents" }, > + { 0, 36, 2, "Dot3StatsFCSErrors" }, > + { 0, 38, 2, "Dot3StatsSymbolErrors" }, > + { 0, 40, 2, "Dot3InPauseFrames" }, > + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, > + { 0, 44, 4, "IfOutOctets" }, > + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, > + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, > + { 0, 52, 2, "Dot3sDeferredTransmissions" }, > + { 0, 54, 2, "Dot3StatsLateCollisions" }, > + { 0, 56, 2, "EtherStatsCollisions" }, > + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, > + { 0, 60, 2, "Dot3OutPauseFrames" }, > + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, > + > + /* > + * The following counters are accessible at a different > + * base address. > + */ > + { 1, 0, 2, "Dot1dTpPortInDiscards" }, > + { 1, 2, 2, "IfOutUcastPkts" }, > + { 1, 4, 2, "IfOutMulticastPkts" }, > + { 1, 6, 2, "IfOutBroadcastPkts" }, > +}; > + > +static int rtl8366s_get_mib_counter(struct realtek_smi *smi, > + int port, > + struct rtl8366_mib_counter *mib, > + u64 *mibvalue) > +{ > + u32 addr, val; > + int ret; > + int i; > + > + switch (mib->base) { > + case 0: > + addr = RTL8366S_MIB_COUNTER_BASE + > + RTL8366S_MIB_COUNTER_PORT_OFFSET * port; > + break; > + case 1: > + addr = RTL8366S_MIB_COUNTER_BASE2 + > + RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; > + break; > + default: > + return -EINVAL; > + } > + > + addr += mib->offset; > + > + /* > + * Writing access counter address first > + * then ASIC will prepare 64bits counter wait for being retrived > + */ > + ret = regmap_write(smi->map, addr, 0); > + if (ret) > + return ret; > + > + /* read MIB control register */ > + ret = regmap_read(smi->map, RTL8366S_MIB_CTRL_REG, &val); > + if (ret) > + return -EIO; > + > + if (val & RTL8366S_MIB_CTRL_BUSY_MASK) > + return -EBUSY; > + > + if (val & RTL8366S_MIB_CTRL_RESET_MASK) > + return -EIO; > + > + /* Read each individual MIB 16 bits at the time */ > + *mibvalue = 0; > + for (i = mib->length; i > 0; i--) { > + ret = regmap_read(smi->map, addr + (i - 1), &val); > + if (ret) > + return ret; > + *mibvalue = (*mibvalue << 16) | (val & 0xFFFF); > + } > + return 0; > +} > + > +static int rtl8366s_phy_read(struct realtek_smi *smi, int phy, int regnum) > +{ > + u32 val; > + u32 reg; > + int ret; > + > + if (phy > RTL8366S_PHY_NO_MAX) > + return -EINVAL; > + > + ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG, > + RTL8366S_PHY_CTRL_READ); > + if (ret) > + return ret; > + > + reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum; > + > + ret = regmap_write(smi->map, reg, 0); > + if (ret) > + return ret; > + > + ret = regmap_read(smi->map, RTL8366S_PHY_ACCESS_DATA_REG, &val); > + if (ret) > + return ret; > + > + return val; > +} > + > +static int rtl8366s_phy_write(struct realtek_smi *smi, int phy, int regnum, > + u16 val) > +{ > + u32 reg; > + int ret; > + > + if (phy > RTL8366S_PHY_NO_MAX) > + return -EINVAL; > + > + ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG, > + RTL8366S_PHY_CTRL_WRITE); > + if (ret) > + return ret; > + > + reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum; > + > + ret = regmap_write(smi->map, reg, val); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int rtl8366s_reset_chip(struct realtek_smi *smi) > +{ > + int timeout = 10; > + u32 val; > + int ret; > + > + realtek_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, > + RTL8366S_CHIP_CTRL_RESET_HW); > + do { > + usleep_range(20000, 25000); > + ret = regmap_read(smi->map, RTL8366S_RESET_CTRL_REG, &val); > + if (ret) > + return ret; > + > + if (!(val & RTL8366S_CHIP_CTRL_RESET_HW)) > + break; > + } while (--timeout); > + > + if (!timeout) { > + dev_err(smi->dev, "timeout waiting for the switch to reset\n"); > + return -EIO; > + } > + > + return 0; > +} > + > +static enum dsa_tag_protocol rtl8366s_get_tag_protocol(struct dsa_switch *ds, > + int port, > + enum dsa_tag_protocol mp) > +{ > + return DSA_TAG_PROTO_RTL8366S; > +} > + > +static void > +rtl8366s_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, > + phy_interface_t interface, struct phy_device *phydev, > + int speed, int duplex, bool tx_pause, bool rx_pause) > +{ > + struct realtek_smi *smi = ds->priv; > + int ret; > + > + if (port != RTL8366S_PORT_NUM_CPU) > + return; > + > + /* Force the fixed CPU port into 1Gbit mode, no autonegotiation */ > + ret = regmap_update_bits(smi->map, RTL8366S_MAC_FORCE_CTRL1_REG, > + BIT(port), BIT(port)); > + if (ret) { > + dev_err(smi->dev, "failed to force 1Gbit on CPU port\n"); > + return; > + } > + > + ret = regmap_update_bits(smi->map, RTL8366S_PAACR2, > + 0xFF00U, > + RTL8366S_PAACR_CPU_PORT << 8); > + if (ret) { > + dev_err(smi->dev, "failed to set PAACR on CPU port\n"); > + return; > + } > + > + /* Enable the CPU port */ > + ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), > + 0); > + if (ret) { > + dev_err(smi->dev, "failed to enable the CPU port\n"); > + return; > + } > +} > + > +static void > +rtl8366s_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, > + phy_interface_t interface) > +{ > + struct realtek_smi *smi = ds->priv; > + int ret; > + > + if (port != RTL8366S_PORT_NUM_CPU) > + return; > + > + /* Disable the CPU port */ > + ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port), > + BIT(port)); > + if (ret) { > + dev_err(smi->dev, "failed to disable the CPU port\n"); > + return; > + } > +} > + > +static int rtl8366s_setup(struct dsa_switch *ds) > +{ > + struct realtek_smi *smi = ds->priv; > + int ret; > + > + /* Reset chip */ > + ret = rtl8366s_reset_chip(smi); > + if (ret) > + return ret; > + > + /* Set up the "green ethernet" feature */ > + ret = regmap_update_bits(smi->map, RTL8366S_GREEN_ETHERNET_CTRL_REG, > + RTL8366S_GREEN_ETHERNET_CTRL_MASK, > + RTL8366S_GREEN_ETHERNET_TX | > + RTL8366S_GREEN_ETHERNET_RX); > + if (ret) > + return ret; > + > + /* Enable CPU port with custom tag 8899 */ > + ret = regmap_write(smi->map, RTL8366S_CPU_CTRL_REG, > + RTL8366S_PORT_CPU); > + if (ret) > + return ret; > + > + /* Make sure we default-enable the fixed CPU port */ > + ret = regmap_update_bits(smi->map, RTL8366S_PECR, > + RTL8366S_PORT_CPU, 0); > + if (ret) > + return ret; > + > + /* Enable learning for all ports */ > + ret = regmap_write(smi->map, RTL8366S_SSCR0, 0); > + if (ret) > + return ret; DSA has a new way of dealing with address learning. For the user ports, .port_pre_bridge_flags and .port_bridge_flags get called now. You should start with address learning disabled and implement those operations. For the CPU port, DSA does not manage address learning (yet). So if you support it there, you need to enable it manually. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver 2021-02-17 12:25 ` Vladimir Oltean @ 2021-02-17 15:44 ` Linus Walleij 0 siblings, 0 replies; 17+ messages in thread From: Linus Walleij @ 2021-02-17 15:44 UTC (permalink / raw) To: Vladimir Oltean Cc: DENG Qingfang, Andrew Lunn, Vivien Didelot, Florian Fainelli, David S. Miller, Jakub Kicinski, netdev, Mauri Sandberg On Wed, Feb 17, 2021 at 1:25 PM Vladimir Oltean <olteanv@gmail.com> wrote: > I'm not going to do a detailed review on a driver that is a 90% copy of > rtl8366rb. You should probably spend some time to avoid duplicating > what is common. The split of common and individual code comes from the OpenWrt driver, maybe it wasn't optimal. Maybe we can move some of the driver into the shared rtl8366.c file. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2021-03-01 13:08 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-02-17 6:21 [RFC net-next 0/2] DSA driver for Realtek RTL8366S/SR DENG Qingfang 2021-02-17 6:21 ` [RFC net-next 1/2] net: dsa: add Realtek RTL8366S switch tag DENG Qingfang 2021-02-17 7:07 ` Heiner Kallweit 2021-02-17 11:01 ` Linus Walleij 2021-02-17 11:28 ` Heiner Kallweit 2021-02-17 10:55 ` Linus Walleij 2021-02-17 12:28 ` DENG Qingfang 2021-02-27 23:47 ` Linus Walleij 2021-02-28 11:32 ` DENG Qingfang 2021-03-01 13:06 ` Linus Walleij 2021-02-17 6:21 ` [RFC net-next 2/2] net: dsa: add Realtek RTL8366S switch driver DENG Qingfang 2021-02-17 7:37 ` kernel test robot 2021-02-17 9:57 ` kernel test robot 2021-02-17 11:12 ` Linus Walleij 2021-02-17 12:45 ` DENG Qingfang 2021-02-17 12:25 ` Vladimir Oltean 2021-02-17 15:44 ` Linus Walleij
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.