Skip to content

Commit

Permalink
Merge branch 'DSA-TX-tstamp'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
The DSA TX timestamping situation

This series is the moral v2 of "[PATCH net] net: dsa: sja1105: Fix
double delivery of TX timestamps to socket error queue" [0] which did
not manage to convince public opinion (actually it didn't convince me
neither).

This fixes PTP timestamping on one particular board, where the DSA
switch is sja1105 and the master is gianfar. Unfortunately there is no
way to make the fix more general without committing logical
inaccuracies: the SKBTX_IN_PROGRESS flag does serve a purpose, even if
the sja1105 driver is not using it now: it prevents delivering a SW
timestamp to the app socket when the HW timestamp will be provided. So
not setting this flag (the approach from v1) might create avoidable
complications in the future (not to mention that there isn't any
satisfactory explanation on why that would be the correct solution).

So the goal of this change set is to create a more strict framework for
DSA master devices when attached to PTP switches, and to fix the first
master driver that is overstepping its duties and is delivering
unsolicited TX timestamps.

[0]: https://www.spinics.net/lists/netdev/msg619699.html
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 28, 2019
2 parents 270fe2c + f685e60 commit 1a1fda5
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
10 changes: 7 additions & 3 deletions drivers/net/ethernet/freescale/gianfar.c
Original file line number Diff line number Diff line change
Expand Up @@ -2205,13 +2205,17 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
skb_dirtytx = tx_queue->skb_dirtytx;

while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
bool do_tstamp;

do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
priv->hwts_tx_en;

frags = skb_shinfo(skb)->nr_frags;

/* When time stamping, one additional TxBD must be freed.
* Also, we need to dma_unmap_single() the TxPAL.
*/
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
if (unlikely(do_tstamp))
nr_txbds = frags + 2;
else
nr_txbds = frags + 1;
Expand All @@ -2225,7 +2229,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
(lstatus & BD_LENGTH_MASK))
break;

if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
if (unlikely(do_tstamp)) {
next = next_txbd(bdp, base, tx_ring_size);
buflen = be16_to_cpu(next->length) +
GMAC_FCB_LEN + GMAC_TXPAL_LEN;
Expand All @@ -2235,7 +2239,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr),
buflen, DMA_TO_DEVICE);

if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
if (unlikely(do_tstamp)) {
struct skb_shared_hwtstamps shhwtstamps;
u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) &
~0x7UL);
Expand Down
30 changes: 30 additions & 0 deletions net/dsa/master.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,35 @@ static int dsa_master_get_phys_port_name(struct net_device *dev,
return 0;
}

static int dsa_master_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct dsa_port *cpu_dp = dev->dsa_ptr;
struct dsa_switch *ds = cpu_dp->ds;
struct dsa_switch_tree *dst;
int err = -EOPNOTSUPP;
struct dsa_port *dp;

dst = ds->dst;

switch (cmd) {
case SIOCGHWTSTAMP:
case SIOCSHWTSTAMP:
/* Deny PTP operations on master if there is at least one
* 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)
return -EBUSY;
break;
}

if (cpu_dp->orig_ndo_ops && cpu_dp->orig_ndo_ops->ndo_do_ioctl)
err = cpu_dp->orig_ndo_ops->ndo_do_ioctl(dev, ifr, cmd);

return err;
}

static int dsa_master_ethtool_setup(struct net_device *dev)
{
struct dsa_port *cpu_dp = dev->dsa_ptr;
Expand Down Expand Up @@ -249,6 +278,7 @@ static int dsa_master_ndo_setup(struct net_device *dev)
memcpy(ops, cpu_dp->orig_ndo_ops, sizeof(*ops));

ops->ndo_get_phys_port_name = dsa_master_get_phys_port_name;
ops->ndo_do_ioctl = dsa_master_ioctl;

dev->netdev_ops = ops;

Expand Down

0 comments on commit 1a1fda5

Please sign in to comment.