summaryrefslogtreecommitdiff
path: root/drivers/net/netkit.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2023-12-04 12:31:42 +0000
committerMark Brown <broonie@kernel.org>2023-12-04 12:31:42 +0000
commit06891af2709b5dfa4081ff1f07b9f4c2743834b7 (patch)
tree672f337b94d3af79268a54b5307af1392f708a1a /drivers/net/netkit.c
parent7a030abc0185b30a3fd19a7431347c6f5a82c588 (diff)
parent9b2ef250b31d46f7ef522bd1bd84942f998bb3f9 (diff)
spi: spl022: fix sleeping in interrupt context
Merge series from Nam Cao <namcao@linutronix.de>: While running the spl022, I got the following warning: BUG: sleeping function called from invalid context at drivers/spi/spi.c:1428 This is because between spi transfers, spi_transfer_delay_exec() (who may sleep if the delay is >10us) is called in interrupt context. This is a problem for anyone who runs this driver and need more than 10us delay. Patch 1 adds an error reporting mechanism, needed by patch 2 who switch to use the default spi_transfer_one_message(), which fix the problem. The series is tested with polling transfer mode and interrupt transfer mode. I can't test the DMA mode, so some help testing here is very appreciated.
Diffstat (limited to 'drivers/net/netkit.c')
-rw-r--r--drivers/net/netkit.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c
index 5a0f86f38f09..97bd6705c241 100644
--- a/drivers/net/netkit.c
+++ b/drivers/net/netkit.c
@@ -7,6 +7,7 @@
#include <linux/filter.h>
#include <linux/netfilter_netdev.h>
#include <linux/bpf_mprog.h>
+#include <linux/indirect_call_wrapper.h>
#include <net/netkit.h>
#include <net/dst.h>
@@ -68,6 +69,7 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_tx_t ret_dev = NET_XMIT_SUCCESS;
const struct bpf_mprog_entry *entry;
struct net_device *peer;
+ int len = skb->len;
rcu_read_lock();
peer = rcu_dereference(nk->peer);
@@ -85,15 +87,22 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev)
case NETKIT_PASS:
skb->protocol = eth_type_trans(skb, skb->dev);
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
- __netif_rx(skb);
+ if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) {
+ dev_sw_netstats_tx_add(dev, 1, len);
+ dev_sw_netstats_rx_add(peer, len);
+ } else {
+ goto drop_stats;
+ }
break;
case NETKIT_REDIRECT:
+ dev_sw_netstats_tx_add(dev, 1, len);
skb_do_redirect(skb);
break;
case NETKIT_DROP:
default:
drop:
kfree_skb(skb);
+drop_stats:
dev_core_stats_tx_dropped_inc(dev);
ret_dev = NET_XMIT_DROP;
break;
@@ -169,11 +178,18 @@ out:
rcu_read_unlock();
}
-static struct net_device *netkit_peer_dev(struct net_device *dev)
+INDIRECT_CALLABLE_SCOPE struct net_device *netkit_peer_dev(struct net_device *dev)
{
return rcu_dereference(netkit_priv(dev)->peer);
}
+static void netkit_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ dev_fetch_sw_netstats(stats, dev->tstats);
+ stats->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
+}
+
static void netkit_uninit(struct net_device *dev);
static const struct net_device_ops netkit_netdev_ops = {
@@ -184,6 +200,7 @@ static const struct net_device_ops netkit_netdev_ops = {
.ndo_set_rx_headroom = netkit_set_headroom,
.ndo_get_iflink = netkit_get_iflink,
.ndo_get_peer_dev = netkit_peer_dev,
+ .ndo_get_stats64 = netkit_get_stats,
.ndo_uninit = netkit_uninit,
.ndo_features_check = passthru_features_check,
};
@@ -218,6 +235,7 @@ static void netkit_setup(struct net_device *dev)
ether_setup(dev);
dev->max_mtu = ETH_MAX_MTU;
+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
dev->flags |= IFF_NOARP;
dev->priv_flags &= ~IFF_TX_SKB_SHARING;