Merge branch 'DSA-TX-tstamp'
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>
This commit is contained in:
commit
1a1fda57b4
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue