]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
net: dsa: make dsa_master_ioctl() see through port_hwtstamp_get() shims
authorVladimir Oltean <vladimir.oltean@nxp.com>
Fri, 11 Nov 2022 21:10:20 +0000 (23:10 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Wed, 14 Dec 2022 12:59:29 +0000 (13:59 +0100)
[ Upstream commit ed1fe1bebe18884b11e5536b5ac42e3a48960835 ]

There are multi-generational drivers like mv88e6xxx which have code like
this:

int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
struct ifreq *ifr)
{
if (!chip->info->ptp_support)
return -EOPNOTSUPP;

...
}

DSA wants to deny PTP timestamping on the master if the switch supports
timestamping too. However it currently relies on the presence of the
port_hwtstamp_get() callback to determine PTP capability, and this
clearly does not work in that case (method is present but returns
-EOPNOTSUPP).

We should not deny PTP on the DSA master for those switches which truly
do not support hardware timestamping.

Create a dsa_port_supports_hwtstamp() method which actually probes for
support by calling port_hwtstamp_get() and seeing whether that returned
-EOPNOTSUPP or not.

Fixes: f685e609a301 ("net: dsa: Deny PTP on master if switch supports it")
Link: https://patchwork.kernel.org/project/netdevbpf/patch/20221110124345.3901389-1-festevam@gmail.com/
Reported-by: Fabio Estevam <festevam@gmail.com>
Reported-by: Steffen Bätz <steffen@innosonix.de>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Fabio Estevam <festevam@denx.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
(cherry picked from commit 97009f07f2176297c2fab340f51e4f8423dd3cb8)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
net/dsa/dsa_priv.h
net/dsa/master.c
net/dsa/port.c

index a5c9bc7b66c6eb37c7552b55a9d56302a71266d2..e91265434354e54ea116ce86b6a51e44a62a32e1 100644 (file)
@@ -198,6 +198,7 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
 }
 
 /* port.c */
+bool dsa_port_supports_hwtstamp(struct dsa_port *dp, struct ifreq *ifr);
 void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
                               const struct dsa_device_ops *tag_ops);
 int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age);
index e8e19857621bda0472ae7f0f65accc89dea995b0..69ec510abe83cb11805c340a672dd5e9c105562f 100644 (file)
@@ -204,8 +204,7 @@ static int dsa_master_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                 * switch in the tree that is PTP capable.
                 */
                list_for_each_entry(dp, &dst->ports, list)
-                       if (dp->ds->ops->port_hwtstamp_get ||
-                           dp->ds->ops->port_hwtstamp_set)
+                       if (dsa_port_supports_hwtstamp(dp, ifr))
                                return -EBUSY;
                break;
        }
index a21015d6bd3651cbd73dec5578feeba0d753a7d4..31e8a7a8c3e60eb347e4a77f9a4a0df9c3400587 100644 (file)
@@ -75,6 +75,22 @@ static bool dsa_port_can_configure_learning(struct dsa_port *dp)
        return !err;
 }
 
+bool dsa_port_supports_hwtstamp(struct dsa_port *dp, struct ifreq *ifr)
+{
+       struct dsa_switch *ds = dp->ds;
+       int err;
+
+       if (!ds->ops->port_hwtstamp_get || !ds->ops->port_hwtstamp_set)
+               return false;
+
+       /* "See through" shim implementations of the "get" method.
+        * This will clobber the ifreq structure, but we will either return an
+        * error, or the master will overwrite it with proper values.
+        */
+       err = ds->ops->port_hwtstamp_get(ds, dp->index, ifr);
+       return err != -EOPNOTSUPP;
+}
+
 int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age)
 {
        struct dsa_switch *ds = dp->ds;