Message ID | 20221121154150.9573-4-arun.ramadoss@microchip.com (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | net: dsa: microchip: add PTP support for KSZ9x and LAN937x | expand |
On Mon, Nov 21, 2022 at 09:11:45PM +0530, Arun Ramadoss wrote: > +static int ksz_ptp_enable_mode(struct ksz_device *dev, bool enable) > +{ > + u16 data = 0; > + > + /* Enable PTP mode */ > + if (enable) > + data = PTP_ENABLE; > + > + return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE, data); > +} > + > +static int ksz_set_hwtstamp_config(struct ksz_device *dev, int port, > + struct hwtstamp_config *config) > +{ > + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev->ds); > + struct ksz_port *prt = &dev->ports[port]; > + bool rx_on; > + > + /* reserved for future extensions */ > + if (config->flags) > + return -EINVAL; > + > + switch (config->tx_type) { > + case HWTSTAMP_TX_OFF: > + case HWTSTAMP_TX_ONESTEP_P2P: > + prt->hwts_tx_en = config->tx_type; > + break; > + case HWTSTAMP_TX_ON: > + if (!is_lan937x(dev)) > + return -ERANGE; > + > + prt->hwts_tx_en = config->tx_type; > + break; > + default: > + return -ERANGE; > + } > + > + switch (config->rx_filter) { > + case HWTSTAMP_FILTER_NONE: > + rx_on = false; > + break; > + default: > + rx_on = true; > + break; > + } > + > + if (rx_on != tagger_data->hwtstamp_get_state(dev->ds)) { > + int ret; > + > + tagger_data->hwtstamp_set_state(dev->ds, false); > + > + ret = ksz_ptp_enable_mode(dev, rx_on); > + if (ret) > + return ret; > + > + if (rx_on) > + tagger_data->hwtstamp_set_state(dev->ds, true); > + } What's your excuse which such a horrible code pattern? What will happen so bad with the packet if it's flagged with a TX timestamp request in KSZ_SKB_CB(skb) at the same time as REG_PTP_MSG_CONF1 is written to? Also, doesn't dev->ports[port].hwts_tx_en serve as a guard against flagging packets for TX timestamps when you shouldn't? > + > + return 0; > +} > diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c > index 37db5156f9a3..6a909a300c13 100644 > --- a/net/dsa/tag_ksz.c > +++ b/net/dsa/tag_ksz.c > @@ -4,6 +4,7 @@ > * Copyright (c) 2017 Microchip Technology > */ > > +#include <linux/dsa/ksz_common.h> > #include <linux/etherdevice.h> > #include <linux/list.h> > #include <net/dsa.h> > @@ -18,6 +19,62 @@ > #define KSZ_EGRESS_TAG_LEN 1 > #define KSZ_INGRESS_TAG_LEN 1 > > +#define KSZ_HWTS_EN 0 > + > +struct ksz_tagger_private { > + struct ksz_tagger_data data; /* Must be first */ > + unsigned long state; > +}; > + > +static struct ksz_tagger_private * > +ksz_tagger_private(struct dsa_switch *ds) > +{ > + return ds->tagger_data; > +} > + > +static bool ksz_hwtstamp_get_state(struct dsa_switch *ds) > +{ > + struct ksz_tagger_private *priv = ksz_tagger_private(ds); > + > + return test_bit(KSZ_HWTS_EN, &priv->state); > +} > + > +static void ksz_hwtstamp_set_state(struct dsa_switch *ds, bool on) > +{ > + struct ksz_tagger_private *priv = ksz_tagger_private(ds); > + > + if (on) > + set_bit(KSZ_HWTS_EN, &priv->state); > + else > + clear_bit(KSZ_HWTS_EN, &priv->state); > +}
Hi Vladimir, Thanks for the comment. On Tue, 2022-11-22 at 01:13 +0200, Vladimir Oltean wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > On Mon, Nov 21, 2022 at 09:11:45PM +0530, Arun Ramadoss wrote: > > +static int ksz_set_hwtstamp_config(struct ksz_device *dev, int > > port, > > + struct hwtstamp_config *config) > > +{ > > + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev- > > >ds); > > + struct ksz_port *prt = &dev->ports[port]; > > + bool rx_on; > > + > > + /* reserved for future extensions */ > > + if (config->flags) > > + return -EINVAL; > > + > > + switch (config->tx_type) { > > + case HWTSTAMP_TX_OFF: > > + case HWTSTAMP_TX_ONESTEP_P2P: > > + prt->hwts_tx_en = config->tx_type; > > + break; > > + case HWTSTAMP_TX_ON: > > + if (!is_lan937x(dev)) > > + return -ERANGE; > > + > > + prt->hwts_tx_en = config->tx_type; > > + break; > > + default: > > + return -ERANGE; > > + } > > + > > + switch (config->rx_filter) { > > + case HWTSTAMP_FILTER_NONE: > > + rx_on = false; > > + break; > > + default: > > + rx_on = true; > > + break; > > + } > > + > > + if (rx_on != tagger_data->hwtstamp_get_state(dev->ds)) { > > + int ret; > > + > > + tagger_data->hwtstamp_set_state(dev->ds, false); > > + > > + ret = ksz_ptp_enable_mode(dev, rx_on); > > + if (ret) > > + return ret; > > + > > + if (rx_on) > > + tagger_data->hwtstamp_set_state(dev->ds, > > true); > > + } > > What's your excuse which such a horrible code pattern? What will > happen > so bad with the packet if it's flagged with a TX timestamp request in > KSZ_SKB_CB(skb) at the same time as REG_PTP_MSG_CONF1 is written to? > > Also, doesn't dev->ports[port].hwts_tx_en serve as a guard against > flagging packets for TX timestamps when you shouldn't? > I took this configuration template routine from other driver. Can I replace above snippet with tagger_data->hwtstamp_set_state(dev->ds, rx_on); ret = ksz_ptp_enable_mode(dev, rx_on); if (ret) return ret; > diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c > > index 37db5156f9a3..6a909a300c13 100644 > > --- a/net/dsa/tag_ksz.c > > +++ b/net/dsa/tag_ksz.c > > @@ -4,6 +4,7 @@ > > * Copyright (c) 2017 Microchip Technology > > */ > > > > +#include <linux/dsa/ksz_common.h> > > #include <linux/etherdevice.h> > > #include <linux/list.h> > > #include <net/dsa.h> > > @@ -18,6 +19,62 @@ > > #define KSZ_EGRESS_TAG_LEN 1 > > #define KSZ_INGRESS_TAG_LEN 1 > > > > +#define KSZ_HWTS_EN 0 > > + > > +struct ksz_tagger_private { > > + struct ksz_tagger_data data; /* Must be first */ > > + unsigned long state; > > +}; > > + > >
On Wed, Nov 23, 2022 at 01:57:47PM +0000, Arun.Ramadoss@microchip.com wrote: > > What's your excuse which such a horrible code pattern? What will happen > > so bad with the packet if it's flagged with a TX timestamp request in > > KSZ_SKB_CB(skb) at the same time as REG_PTP_MSG_CONF1 is written to? > > > > Also, doesn't dev->ports[port].hwts_tx_en serve as a guard against > > flagging packets for TX timestamps when you shouldn't? > > > > I took this configuration template routine from other driver. Not really a good excuse. The sja1105 driver has more hardware-specific issues to deal with, not necessarily the same as ksz. > Can I replace above snippet with > > tagger_data->hwtstamp_set_state(dev->ds, rx_on); > ret = ksz_ptp_enable_mode(dev, rx_on); > if (ret) > return ret; Why do you need to call hwtstamp_set_state anyway?
On Thu, 2022-11-24 at 12:22 +0200, Vladimir Oltean wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > On Wed, Nov 23, 2022 at 01:57:47PM +0000, Arun.Ramadoss@microchip.com > wrote: > > > What's your excuse which such a horrible code pattern? What will > > > happen > > > so bad with the packet if it's flagged with a TX timestamp > > > request in > > > KSZ_SKB_CB(skb) at the same time as REG_PTP_MSG_CONF1 is written > > > to? > > > > > > Also, doesn't dev->ports[port].hwts_tx_en serve as a guard > > > against > > > flagging packets for TX timestamps when you shouldn't? > > > > > > > I took this configuration template routine from other driver. Mistake here. It is carried forwarded from Christian Eggers patch. > > Not really a good excuse. The sja1105 driver has more hardware- > specific > issues to deal with, not necessarily the same as ksz. > > > Can I replace above snippet with > > > > tagger_data->hwtstamp_set_state(dev->ds, rx_on); > > ret = ksz_ptp_enable_mode(dev, rx_on); > > if (ret) > > return ret; > > Why do you need to call hwtstamp_set_state anyway? In tag_ksz.c, xmit function query this state, to determine whether to allocate the 4 PTP timestamp bytes in the skb_buffer or not. Using this tagger_data set state, ptp enable and disable is communicated between ksz_ptp.c and tag_ksz.c
On Thu, Nov 24, 2022 at 10:52:46AM +0000, Arun.Ramadoss@microchip.com wrote: > Mistake here. It is carried forwarded from Christian Eggers patch. Still taken from sja1105_hwtstamp_set(). Anyway, doesn't matter where it's taken from, as long as it has a justification for being there. > > Why do you need to call hwtstamp_set_state anyway? > > In tag_ksz.c, xmit function query this state, to determine whether to > allocate the 4 PTP timestamp bytes in the skb_buffer or not. Using this > tagger_data set state, ptp enable and disable is communicated between > ksz_ptp.c and tag_ksz.c Why do you need to query this state in particular, considering that the skb goes first through the port_txtstamp() dsa_switch_ops function? Can't you just check there if TX timestamping is enabled, and leave a mark in KSZ_SKB_CB()?
Hi Vladimir, On Thu, 2022-11-24 at 16:14 +0200, Vladimir Oltean wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > On Thu, Nov 24, 2022 at 10:52:46AM +0000, Arun.Ramadoss@microchip.com > wrote: > > Mistake here. It is carried forwarded from Christian Eggers patch. > > Still taken from sja1105_hwtstamp_set(). Anyway, doesn't matter where > it's taken from, as long as it has a justification for being there. > > > > Why do you need to call hwtstamp_set_state anyway? > > > > In tag_ksz.c, xmit function query this state, to determine whether > > to > > allocate the 4 PTP timestamp bytes in the skb_buffer or not. Using > > this > > tagger_data set state, ptp enable and disable is communicated > > between > > ksz_ptp.c and tag_ksz.c > > Why do you need to query this state in particular, considering that > the > skb goes first through the port_txtstamp() dsa_switch_ops function? > Can't you just check there if TX timestamping is enabled, and leave a > mark in KSZ_SKB_CB()? KSZ switches need a additional 4 bytes in tail tag if the PTP is enabled in hardware. If the PTP is enabled and if we didn't add 4 additional bytes in the tail tag then packets are corrupted. Tristram explained this in the patch conversation https://lore.kernel.org/netdev/20201118203013.5077-1-ceggers@arri.de/T/#mb3eba4918bda351a405168e7a2140d29262f4c63 I did the follwing experiment today, * Removed the ptp time stamp check in tag_ksz.c. In the ksz_xmit function, 4 additional bytes are added only if KSZ_SKB_CB->ts_en bit is set. * Setup the board, ping two boards. Ping is successful. * Run the ptpl in the background * Now if I run the ping, ping is not successful. And also in the ptp4l log message it shows as bad message received. We need a mechanism to inform tag_ksz.c to add 4 additional bytes in tail_tag for all the packets if the ptp is enabled in the hardware.
On Fri, Nov 25, 2022 at 07:06:07AM +0000, Arun.Ramadoss@microchip.com wrote: > KSZ switches need a additional 4 bytes in tail tag if the PTP is > enabled in hardware. If the PTP is enabled and if we didn't add 4 > additional bytes in the tail tag then packets are corrupted. > > Tristram explained this in the patch conversation > > https://lore.kernel.org/netdev/20201118203013.5077-1-ceggers@arri.de/T/#mb3eba4918bda351a405168e7a2140d29262f4c63 > > I did the follwing experiment today, > * Removed the ptp time stamp check in tag_ksz.c. In the ksz_xmit > function, 4 additional bytes are added only if KSZ_SKB_CB->ts_en bit is > set. > * Setup the board, ping two boards. Ping is successful. > * Run the ptpl in the background > * Now if I run the ping, ping is not successful. And also in the ptp4l > log message it shows as bad message received. > > We need a mechanism to inform tag_ksz.c to add 4 additional bytes in > tail_tag for all the packets if the ptp is enabled in the hardware. Ok. The code + comments need to be sufficiently self-explanatory that this question does not get asked again. It will not be trivial to do a proper job documenting the hardware oddities as a justification for the software workarounds, but it should be possible.
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index eb77eca0dcb2..0abbb2ebcd00 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2873,6 +2873,8 @@ static const struct dsa_switch_ops ksz_switch_ops = { .port_change_mtu = ksz_change_mtu, .port_max_mtu = ksz_max_mtu, .get_ts_info = ksz_get_ts_info, + .port_hwtstamp_get = ksz_hwtstamp_get, + .port_hwtstamp_set = ksz_hwtstamp_set, }; struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 767f17d2c75d..605d0a295288 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -104,6 +104,9 @@ struct ksz_port { struct ksz_device *ksz_dev; struct ksz_irq pirq; u8 num; +#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) + u8 hwts_tx_en; +#endif }; struct ksz_device { diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index cad0c6087419..1b2880d013ed 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -3,6 +3,7 @@ * Copyright (C) 2021-2022 Microchip Technology Inc. */ +#include <linux/dsa/ksz_common.h> #include <linux/kernel.h> #include <linux/ptp_classify.h> #include <linux/ptp_clock_kernel.h> @@ -21,6 +22,17 @@ #define KSZ_PTP_INC_NS 40 /* HW clock is incremented every 40 ns (by 40) */ #define KSZ_PTP_SUBNS_BITS 32 /* Number of bits in sub-nanoseconds counter */ +static int ksz_ptp_enable_mode(struct ksz_device *dev, bool enable) +{ + u16 data = 0; + + /* Enable PTP mode */ + if (enable) + data = PTP_ENABLE; + + return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE, data); +} + /* The function is return back the capability of timestamping feature when * requested through ethtool -T <interface> utility */ @@ -33,15 +45,114 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts) SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; - ts->tx_types = (1 << HWTSTAMP_TX_OFF); + ts->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ONESTEP_P2P); + + if (is_lan937x(dev)) + ts->tx_types |= (1 << HWTSTAMP_TX_ON); - ts->rx_filters = (1 << HWTSTAMP_FILTER_NONE); + ts->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_ALL); ts->phc_index = ptp_clock_index(ptp_data->clock); return 0; } +int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(ds); + struct ksz_device *dev = ds->priv; + struct hwtstamp_config config; + + config.flags = 0; + + config.tx_type = dev->ports[port].hwts_tx_en; + + if (tagger_data->hwtstamp_get_state(ds)) + config.rx_filter = HWTSTAMP_FILTER_ALL; + else + config.rx_filter = HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int ksz_set_hwtstamp_config(struct ksz_device *dev, int port, + struct hwtstamp_config *config) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev->ds); + struct ksz_port *prt = &dev->ports[port]; + bool rx_on; + + /* reserved for future extensions */ + if (config->flags) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ONESTEP_P2P: + prt->hwts_tx_en = config->tx_type; + break; + case HWTSTAMP_TX_ON: + if (!is_lan937x(dev)) + return -ERANGE; + + prt->hwts_tx_en = config->tx_type; + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + rx_on = false; + break; + default: + rx_on = true; + break; + } + + if (rx_on != tagger_data->hwtstamp_get_state(dev->ds)) { + int ret; + + tagger_data->hwtstamp_set_state(dev->ds, false); + + ret = ksz_ptp_enable_mode(dev, rx_on); + if (ret) + return ret; + + if (rx_on) + tagger_data->hwtstamp_set_state(dev->ds, true); + } + + return 0; +} + +int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + struct hwtstamp_config config; + int ret; + + mutex_lock(&ptp_data->lock); + + ret = copy_from_user(&config, ifr->ifr_data, sizeof(config)); + if (ret) + goto error_return; + + ret = ksz_set_hwtstamp_config(dev, port, &config); + if (ret) + goto error_return; + + /* Save the chosen configuration to be returned later. */ + ret = copy_to_user(ifr->ifr_data, &config, sizeof(config)); + +error_return: + mutex_unlock(&ptp_data->lock); + return ret; +} + /* These are function related to the ptp clock info */ static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) { diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index ac53b0df2733..4c024cc9d935 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -21,6 +21,8 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds); int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); +int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); +int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); #else @@ -38,6 +40,18 @@ static inline void ksz_ptp_clock_unregister(struct dsa_switch *ds) { } #define ksz_get_ts_info NULL +static inline int ksz_hwtstamp_get(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + +static inline int ksz_hwtstamp_set(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + #endif /* End of CONFIG_NET_DSA_MICROCHIOP_KSZ_PTP */ #endif diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h new file mode 100644 index 000000000000..8903bce4753b --- /dev/null +++ b/include/linux/dsa/ksz_common.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip switch tag common header + * + * Copyright (C) 2021-2022 Microchip Technology Inc. + */ + +#ifndef _NET_DSA_KSZ_COMMON_H_ +#define _NET_DSA_KSZ_COMMON_H_ + +#include <net/dsa.h> + +struct ksz_tagger_data { + bool (*hwtstamp_get_state)(struct dsa_switch *ds); + void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); +}; + +static inline struct ksz_tagger_data * +ksz_tagger_data(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +#endif /* _NET_DSA_KSZ_COMMON_H_ */ diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 37db5156f9a3..6a909a300c13 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -4,6 +4,7 @@ * Copyright (c) 2017 Microchip Technology */ +#include <linux/dsa/ksz_common.h> #include <linux/etherdevice.h> #include <linux/list.h> #include <net/dsa.h> @@ -18,6 +19,62 @@ #define KSZ_EGRESS_TAG_LEN 1 #define KSZ_INGRESS_TAG_LEN 1 +#define KSZ_HWTS_EN 0 + +struct ksz_tagger_private { + struct ksz_tagger_data data; /* Must be first */ + unsigned long state; +}; + +static struct ksz_tagger_private * +ksz_tagger_private(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +static bool ksz_hwtstamp_get_state(struct dsa_switch *ds) +{ + struct ksz_tagger_private *priv = ksz_tagger_private(ds); + + return test_bit(KSZ_HWTS_EN, &priv->state); +} + +static void ksz_hwtstamp_set_state(struct dsa_switch *ds, bool on) +{ + struct ksz_tagger_private *priv = ksz_tagger_private(ds); + + if (on) + set_bit(KSZ_HWTS_EN, &priv->state); + else + clear_bit(KSZ_HWTS_EN, &priv->state); +} + +static void ksz_disconnect(struct dsa_switch *ds) +{ + struct ksz_tagger_private *priv = ds->tagger_data; + + kfree(priv); + ds->tagger_data = NULL; +} + +static int ksz_connect(struct dsa_switch *ds) +{ + struct ksz_tagger_data *tagger_data; + struct ksz_tagger_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Export functions for switch driver use */ + tagger_data = &priv->data; + tagger_data->hwtstamp_get_state = ksz_hwtstamp_get_state; + tagger_data->hwtstamp_set_state = ksz_hwtstamp_set_state; + ds->tagger_data = priv; + + return 0; +} + static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, struct net_device *dev, unsigned int port, unsigned int len) @@ -156,6 +213,8 @@ static const struct dsa_device_ops ksz9477_netdev_ops = { .proto = DSA_TAG_PROTO_KSZ9477, .xmit = ksz9477_xmit, .rcv = ksz9477_rcv, + .connect = ksz_connect, + .disconnect = ksz_disconnect, .needed_tailroom = KSZ9477_INGRESS_TAG_LEN, }; @@ -192,6 +251,8 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { .proto = DSA_TAG_PROTO_KSZ9893, .xmit = ksz9893_xmit, .rcv = ksz9477_rcv, + .connect = ksz_connect, + .disconnect = ksz_disconnect, .needed_tailroom = KSZ_INGRESS_TAG_LEN, }; @@ -250,6 +311,8 @@ static const struct dsa_device_ops lan937x_netdev_ops = { .proto = DSA_TAG_PROTO_LAN937X, .xmit = lan937x_xmit, .rcv = ksz9477_rcv, + .connect = ksz_connect, + .disconnect = ksz_disconnect, .needed_tailroom = LAN937X_EGRESS_TAG_LEN, };