Skip to content

Commit a68578c

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: Make deferred_xmit private to sja1105
There are 3 things that are wrong with the DSA deferred xmit mechanism: 1. Its introduction has made the DSA hotpath ever so slightly more inefficient for everybody, since DSA_SKB_CB(skb)->deferred_xmit needs to be initialized to false for every transmitted frame, in order to figure out whether the driver requested deferral or not (a very rare occasion, rare even for the only driver that does use this mechanism: sja1105). That was necessary to avoid kfree_skb from freeing the skb. 2. Because L2 PTP is a link-local protocol like STP, it requires management routes and deferred xmit with this switch. But as opposed to STP, the deferred work mechanism needs to schedule the packet rather quickly for the TX timstamp to be collected in time and sent to user space. But there is no provision for controlling the scheduling priority of this deferred xmit workqueue. Too bad this is a rather specific requirement for a feature that nobody else uses (more below). 3. Perhaps most importantly, it makes the DSA core adhere a bit too much to the NXP company-wide policy "Innovate Where It Doesn't Matter". The sja1105 is probably the only DSA switch that requires some frames sent from the CPU to be routed to the slave port via an out-of-band configuration (register write) rather than in-band (DSA tag). And there are indeed very good reasons to not want to do that: if that out-of-band register is at the other end of a slow bus such as SPI, then you limit that Ethernet flow's throughput to effectively the throughput of the SPI bus. So hardware vendors should definitely not be encouraged to design this way. We do _not_ want more widespread use of this mechanism. Luckily we have a solution for each of the 3 issues: For 1, we can just remove that variable in the skb->cb and counteract the effect of kfree_skb with skb_get, much to the same effect. The advantage, of course, being that anybody who doesn't use deferred xmit doesn't need to do any extra operation in the hotpath. For 2, we can create a kernel thread for each port's deferred xmit work. If the user switch ports are named swp0, swp1, swp2, the kernel threads will be named swp0_xmit, swp1_xmit, swp2_xmit (there appears to be a 15 character length limit on kernel thread names). With this, the user can change the scheduling priority with chrt $(pidof swp2_xmit). For 3, we can actually move the entire implementation to the sja1105 driver. So this patch deletes the generic implementation from the DSA core and adds a new one, more adequate to the requirements of PTP TX timestamping, in sja1105_main.c. Suggested-by: Florian Fainelli <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0a51826 commit a68578c

File tree

6 files changed

+93
-69
lines changed

6 files changed

+93
-69
lines changed

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,16 @@ static int sja1105_setup(struct dsa_switch *ds)
17321732
static void sja1105_teardown(struct dsa_switch *ds)
17331733
{
17341734
struct sja1105_private *priv = ds->priv;
1735+
int port;
1736+
1737+
for (port = 0; port < SJA1105_NUM_PORTS; port++) {
1738+
struct sja1105_port *sp = &priv->ports[port];
1739+
1740+
if (!dsa_is_user_port(ds, port))
1741+
continue;
1742+
1743+
kthread_destroy_worker(sp->xmit_worker);
1744+
}
17351745

17361746
sja1105_tas_teardown(ds);
17371747
sja1105_ptp_clock_unregister(ds);
@@ -1753,6 +1763,18 @@ static int sja1105_port_enable(struct dsa_switch *ds, int port,
17531763
return 0;
17541764
}
17551765

1766+
static void sja1105_port_disable(struct dsa_switch *ds, int port)
1767+
{
1768+
struct sja1105_private *priv = ds->priv;
1769+
struct sja1105_port *sp = &priv->ports[port];
1770+
1771+
if (!dsa_is_user_port(ds, port))
1772+
return;
1773+
1774+
kthread_cancel_work_sync(&sp->xmit_work);
1775+
skb_queue_purge(&sp->xmit_queue);
1776+
}
1777+
17561778
static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
17571779
struct sk_buff *skb, bool takets)
17581780
{
@@ -1811,31 +1833,36 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
18111833
return NETDEV_TX_OK;
18121834
}
18131835

1836+
#define work_to_port(work) \
1837+
container_of((work), struct sja1105_port, xmit_work)
1838+
#define tagger_to_sja1105(t) \
1839+
container_of((t), struct sja1105_private, tagger_data)
1840+
18141841
/* Deferred work is unfortunately necessary because setting up the management
18151842
* route cannot be done from atomit context (SPI transfer takes a sleepable
18161843
* lock on the bus)
18171844
*/
1818-
static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port,
1819-
struct sk_buff *skb)
1845+
static void sja1105_port_deferred_xmit(struct kthread_work *work)
18201846
{
1821-
struct sja1105_private *priv = ds->priv;
1822-
struct sk_buff *clone;
1823-
1824-
mutex_lock(&priv->mgmt_lock);
1847+
struct sja1105_port *sp = work_to_port(work);
1848+
struct sja1105_tagger_data *tagger_data = sp->data;
1849+
struct sja1105_private *priv = tagger_to_sja1105(tagger_data);
1850+
int port = sp - priv->ports;
1851+
struct sk_buff *skb;
18251852

1826-
/* The clone, if there, was made by dsa_skb_tx_timestamp */
1827-
clone = DSA_SKB_CB(skb)->clone;
1853+
while ((skb = skb_dequeue(&sp->xmit_queue)) != NULL) {
1854+
struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
18281855

1829-
sja1105_mgmt_xmit(ds, port, 0, skb, !!clone);
1856+
mutex_lock(&priv->mgmt_lock);
18301857

1831-
if (!clone)
1832-
goto out;
1858+
sja1105_mgmt_xmit(priv->ds, port, 0, skb, !!clone);
18331859

1834-
sja1105_ptp_txtstamp_skb(ds, port, clone);
1860+
/* The clone, if there, was made by dsa_skb_tx_timestamp */
1861+
if (clone)
1862+
sja1105_ptp_txtstamp_skb(priv->ds, port, clone);
18351863

1836-
out:
1837-
mutex_unlock(&priv->mgmt_lock);
1838-
return NETDEV_TX_OK;
1864+
mutex_unlock(&priv->mgmt_lock);
1865+
}
18391866
}
18401867

18411868
/* The MAXAGE setting belongs to the L2 Forwarding Parameters table,
@@ -1966,6 +1993,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
19661993
.get_sset_count = sja1105_get_sset_count,
19671994
.get_ts_info = sja1105_get_ts_info,
19681995
.port_enable = sja1105_port_enable,
1996+
.port_disable = sja1105_port_disable,
19691997
.port_fdb_dump = sja1105_fdb_dump,
19701998
.port_fdb_add = sja1105_fdb_add,
19711999
.port_fdb_del = sja1105_fdb_del,
@@ -1979,7 +2007,6 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
19792007
.port_mdb_prepare = sja1105_mdb_prepare,
19802008
.port_mdb_add = sja1105_mdb_add,
19812009
.port_mdb_del = sja1105_mdb_del,
1982-
.port_deferred_xmit = sja1105_port_deferred_xmit,
19832010
.port_hwtstamp_get = sja1105_hwtstamp_get,
19842011
.port_hwtstamp_set = sja1105_hwtstamp_set,
19852012
.port_rxtstamp = sja1105_port_rxtstamp,
@@ -2031,7 +2058,7 @@ static int sja1105_probe(struct spi_device *spi)
20312058
struct device *dev = &spi->dev;
20322059
struct sja1105_private *priv;
20332060
struct dsa_switch *ds;
2034-
int rc, i;
2061+
int rc, port;
20352062

20362063
if (!dev->of_node) {
20372064
dev_err(dev, "No DTS bindings for SJA1105 driver\n");
@@ -2096,15 +2123,42 @@ static int sja1105_probe(struct spi_device *spi)
20962123
return rc;
20972124

20982125
/* Connections between dsa_port and sja1105_port */
2099-
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
2100-
struct sja1105_port *sp = &priv->ports[i];
2126+
for (port = 0; port < SJA1105_NUM_PORTS; port++) {
2127+
struct sja1105_port *sp = &priv->ports[port];
2128+
struct dsa_port *dp = dsa_to_port(ds, port);
2129+
struct net_device *slave;
2130+
2131+
if (!dsa_is_user_port(ds, port))
2132+
continue;
21012133

2102-
dsa_to_port(ds, i)->priv = sp;
2103-
sp->dp = dsa_to_port(ds, i);
2134+
dp->priv = sp;
2135+
sp->dp = dp;
21042136
sp->data = tagger_data;
2137+
slave = dp->slave;
2138+
kthread_init_work(&sp->xmit_work, sja1105_port_deferred_xmit);
2139+
sp->xmit_worker = kthread_create_worker(0, "%s_xmit",
2140+
slave->name);
2141+
if (IS_ERR(sp->xmit_worker)) {
2142+
rc = PTR_ERR(sp->xmit_worker);
2143+
dev_err(ds->dev,
2144+
"failed to create deferred xmit thread: %d\n",
2145+
rc);
2146+
goto out;
2147+
}
2148+
skb_queue_head_init(&sp->xmit_queue);
21052149
}
21062150

21072151
return 0;
2152+
out:
2153+
while (port-- > 0) {
2154+
struct sja1105_port *sp = &priv->ports[port];
2155+
2156+
if (!dsa_is_user_port(ds, port))
2157+
continue;
2158+
2159+
kthread_destroy_worker(sp->xmit_worker);
2160+
}
2161+
return rc;
21082162
}
21092163

21102164
static int sja1105_remove(struct spi_device *spi)

include/linux/dsa/sja1105.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ struct sja1105_skb_cb {
5353
((struct sja1105_skb_cb *)DSA_SKB_CB_PRIV(skb))
5454

5555
struct sja1105_port {
56+
struct kthread_worker *xmit_worker;
57+
struct kthread_work xmit_work;
58+
struct sk_buff_head xmit_queue;
5659
struct sja1105_tagger_data *data;
5760
struct dsa_port *dp;
5861
bool hwts_tx_en;

include/net/dsa.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ struct dsa_device_ops {
9090

9191
struct dsa_skb_cb {
9292
struct sk_buff *clone;
93-
bool deferred_xmit;
9493
};
9594

9695
struct __dsa_skb_cb {
@@ -192,9 +191,6 @@ struct dsa_port {
192191
struct phylink *pl;
193192
struct phylink_config pl_config;
194193

195-
struct work_struct xmit_work;
196-
struct sk_buff_head xmit_queue;
197-
198194
struct list_head list;
199195

200196
/*
@@ -564,11 +560,6 @@ struct dsa_switch_ops {
564560
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
565561
struct sk_buff *skb, unsigned int type);
566562

567-
/*
568-
* Deferred frame Tx
569-
*/
570-
netdev_tx_t (*port_deferred_xmit)(struct dsa_switch *ds, int port,
571-
struct sk_buff *skb);
572563
/* Devlink parameters */
573564
int (*devlink_param_get)(struct dsa_switch *ds, u32 id,
574565
struct devlink_param_gset_ctx *ctx);

net/dsa/dsa_priv.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,6 @@ int dsa_slave_resume(struct net_device *slave_dev);
162162
int dsa_slave_register_notifier(void);
163163
void dsa_slave_unregister_notifier(void);
164164

165-
void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev);
166-
167165
static inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev)
168166
{
169167
struct dsa_slave_priv *p = netdev_priv(dev);

net/dsa/slave.c

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,6 @@ static int dsa_slave_close(struct net_device *dev)
116116
struct net_device *master = dsa_slave_to_master(dev);
117117
struct dsa_port *dp = dsa_slave_to_port(dev);
118118

119-
cancel_work_sync(&dp->xmit_work);
120-
skb_queue_purge(&dp->xmit_queue);
121-
122119
phylink_stop(dp->pl);
123120

124121
dsa_port_disable(dp);
@@ -518,7 +515,6 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
518515
s->tx_bytes += skb->len;
519516
u64_stats_update_end(&s->syncp);
520517

521-
DSA_SKB_CB(skb)->deferred_xmit = false;
522518
DSA_SKB_CB(skb)->clone = NULL;
523519

524520
/* Identify PTP protocol packets, clone them, and pass them to the
@@ -531,39 +527,13 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
531527
*/
532528
nskb = p->xmit(skb, dev);
533529
if (!nskb) {
534-
if (!DSA_SKB_CB(skb)->deferred_xmit)
535-
kfree_skb(skb);
530+
kfree_skb(skb);
536531
return NETDEV_TX_OK;
537532
}
538533

539534
return dsa_enqueue_skb(nskb, dev);
540535
}
541536

542-
void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev)
543-
{
544-
struct dsa_port *dp = dsa_slave_to_port(dev);
545-
546-
DSA_SKB_CB(skb)->deferred_xmit = true;
547-
548-
skb_queue_tail(&dp->xmit_queue, skb);
549-
schedule_work(&dp->xmit_work);
550-
return NULL;
551-
}
552-
EXPORT_SYMBOL_GPL(dsa_defer_xmit);
553-
554-
static void dsa_port_xmit_work(struct work_struct *work)
555-
{
556-
struct dsa_port *dp = container_of(work, struct dsa_port, xmit_work);
557-
struct dsa_switch *ds = dp->ds;
558-
struct sk_buff *skb;
559-
560-
if (unlikely(!ds->ops->port_deferred_xmit))
561-
return;
562-
563-
while ((skb = skb_dequeue(&dp->xmit_queue)) != NULL)
564-
ds->ops->port_deferred_xmit(ds, dp->index, skb);
565-
}
566-
567537
/* ethtool operations *******************************************************/
568538

569539
static void dsa_slave_get_drvinfo(struct net_device *dev,
@@ -1367,9 +1337,6 @@ int dsa_slave_suspend(struct net_device *slave_dev)
13671337
if (!netif_running(slave_dev))
13681338
return 0;
13691339

1370-
cancel_work_sync(&dp->xmit_work);
1371-
skb_queue_purge(&dp->xmit_queue);
1372-
13731340
netif_device_detach(slave_dev);
13741341

13751342
rtnl_lock();
@@ -1455,8 +1422,6 @@ int dsa_slave_create(struct dsa_port *port)
14551422
}
14561423
p->dp = port;
14571424
INIT_LIST_HEAD(&p->mall_tc_list);
1458-
INIT_WORK(&port->xmit_work, dsa_port_xmit_work);
1459-
skb_queue_head_init(&port->xmit_queue);
14601425
p->xmit = cpu_dp->tag_ops->xmit;
14611426
port->slave = slave_dev;
14621427

net/dsa/tag_sja1105.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev)
8383
return false;
8484
}
8585

86+
/* Calls sja1105_port_deferred_xmit in sja1105_main.c */
87+
static struct sk_buff *sja1105_defer_xmit(struct sja1105_port *sp,
88+
struct sk_buff *skb)
89+
{
90+
/* Increase refcount so the kfree_skb in dsa_slave_xmit
91+
* won't really free the packet.
92+
*/
93+
skb_queue_tail(&sp->xmit_queue, skb_get(skb));
94+
kthread_queue_work(sp->xmit_worker, &sp->xmit_work);
95+
96+
return NULL;
97+
}
98+
8699
static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
87100
struct net_device *netdev)
88101
{
@@ -97,7 +110,7 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
97110
* is the .port_deferred_xmit driver callback.
98111
*/
99112
if (unlikely(sja1105_is_link_local(skb)))
100-
return dsa_defer_xmit(skb, netdev);
113+
return sja1105_defer_xmit(dp->priv, skb);
101114

102115
/* If we are under a vlan_filtering bridge, IP termination on
103116
* switch ports based on 802.1Q tags is simply too brittle to

0 commit comments

Comments
 (0)