diff --git a/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/net/20-smp-tune b/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/net/20-smp-tune new file mode 100644 index 000000000..ab9a90418 --- /dev/null +++ b/feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/net/20-smp-tune @@ -0,0 +1,67 @@ +#!/bin/sh +[ "$ACTION" = add ] || exit + +NPROCS="$(grep -c "^processor.*:" /proc/cpuinfo)" +[ "$NPROCS" -gt 1 ] || exit + +PROC_MASK="$(( (1 << $NPROCS) - 1 ))" + +find_irq_cpu() { + local dev="$1" + local match="$(grep -m 1 "$dev\$" /proc/interrupts)" + local cpu=0 + + [ -n "$match" ] && { + set -- $match + shift + for cur in `seq 1 $NPROCS`; do + [ "$1" -gt 0 ] && { + cpu=$(($cur - 1)) + break + } + shift + done + } + + echo "$cpu" +} + +set_hex_val() { + local file="$1" + local val="$2" + val="$(printf %x "$val")" + [ -n "$DEBUG" ] && echo "$file = $val" + echo "$val" > "$file" +} + +default_ps="$(uci get "network.@globals[0].default_ps")" +[ -n "$default_ps" -a "$default_ps" != 1 ] && exit 0 + +exec 512>/var/lock/smp_tune.lock +flock 512 || exit 1 + +for dev in /sys/class/net/*; do + [ -d "$dev" ] || continue + + # ignore virtual interfaces + [ -n "$(ls "${dev}/" | grep '^lower_')" ] && continue + [ -d "${dev}/device" ] || continue + + device="$(readlink "${dev}/device")" + device="$(basename "$device")" + irq_cpu="$(find_irq_cpu "$device")" + irq_cpu_mask="$((1 << $irq_cpu))" + + for q in ${dev}/queues/rx-*; do + set_hex_val "$q/rps_cpus" "$(($PROC_MASK & ~$irq_cpu_mask))" + done + + ntxq="$(ls -d ${dev}/queues/tx-* | wc -l)" + + idx=$(($irq_cpu + 1)) + for q in ${dev}/queues/tx-*; do + set_hex_val "$q/xps_cpus" "$((1 << $idx))" + let "idx = idx + 1" + [ "$idx" -ge "$NPROCS" ] && idx=0 + done +done diff --git a/feeds/ipq807x/ipq807x/base-files/etc/init.d/smp b/feeds/ipq807x/ipq807x/base-files/etc/init.d/smp new file mode 100755 index 000000000..2fa6cce4e --- /dev/null +++ b/feeds/ipq807x/ipq807x/base-files/etc/init.d/smp @@ -0,0 +1,58 @@ +#!/bin/sh /etc/rc.common + +START=80 + +set_affinity() { + local affinity=$1 + local name=$2 + local irq=`grep -E -m1 $name /proc/interrupts | cut -d ':' -f 1 | tail -n1 | tr -d ' '` + [ -n "$irq" ] && { + logger ath11k setting affinity for $name/$irq to $affinity + echo $affinity > /proc/irq/$irq/smp_affinity + } +} + +boot() { + . /lib/functions/system.sh + + board=$(board_name) + case $board in + cig,wf196) + set_affinity 1 reo2host-destination-ring2 + set_affinity 2 reo2host-destination-ring1 + ;; + *) + set_affinity 2 reo2host-destination-ring2 + set_affinity 1 reo2host-destination-ring1 + ;; + esac + + case $board in + maple) + ;; + *) + set_affinity 8 reo2host-destination-ring4 + set_affinity 4 reo2host-destination-ring3 + + set_affinity 8 wbm2host-tx-completions-ring3 + set_affinity 4 wbm2host-tx-completions-ring2 + set_affinity 2 wbm2host-tx-completions-ring1 + + set_affinity 8 ppdu-end-interrupts-mac1 + set_affinity 8 rxdma2host-monitor-status-ring-mac1 + set_affinity 8 rxdma2host-monitor-destination-mac1 + set_affinity 8 host2rxdma-monitor-ring1 + ;; + esac + + set_affinity 4 ppdu-end-interrupts-mac2 + set_affinity 4 rxdma2host-monitor-status-ring-mac2 + set_affinity 4 rxdma2host-monitor-destination-mac2 + set_affinity 4 host2rxdma-monitor-ring2 + + set_affinity 2 ppdu-end-interrupts-mac3 + set_affinity 2 rxdma2host-monitor-status-ring-mac3 + set_affinity 2 rxdma2host-monitor-destination-mac3 + set_affinity 2 host2rxdma-monitor-ring3 +} + diff --git a/feeds/ipq807x/ipq807x/patches/210-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch b/feeds/ipq807x/ipq807x/patches/210-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch new file mode 100644 index 000000000..961140aab --- /dev/null +++ b/feeds/ipq807x/ipq807x/patches/210-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Date: Mon, 8 Feb 2021 11:34:08 -0800 +Subject: [PATCH] net: extract napi poll functionality to __napi_poll() + +This commit introduces a new function __napi_poll() which does the main +logic of the existing napi_poll() function, and will be called by other +functions in later commits. +This idea and implementation is done by Felix Fietkau and +is proposed as part of the patch to move napi work to work_queue +context. +This commit by itself is a code restructure. + +Signed-off-by: Felix Fietkau +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6322,15 +6322,10 @@ void netif_napi_del(struct napi_struct * + } + EXPORT_SYMBOL(netif_napi_del); + +-static int napi_poll(struct napi_struct *n, struct list_head *repoll) ++static int __napi_poll(struct napi_struct *n, bool *repoll) + { +- void *have; + int work, weight; + +- list_del_init(&n->poll_list); +- +- have = netpoll_poll_lock(n); +- + weight = n->weight; + + /* This NAPI_STATE_SCHED test is for avoiding a race +@@ -6348,7 +6343,7 @@ static int napi_poll(struct napi_struct + WARN_ON_ONCE(work > weight); + + if (likely(work < weight)) +- goto out_unlock; ++ return work; + + /* Drivers must not modify the NAPI state if they + * consume the entire weight. In such cases this code +@@ -6357,7 +6352,7 @@ static int napi_poll(struct napi_struct + */ + if (unlikely(napi_disable_pending(n))) { + napi_complete(n); +- goto out_unlock; ++ return work; + } + + if (n->gro_bitmask) { +@@ -6375,12 +6370,29 @@ static int napi_poll(struct napi_struct + if (unlikely(!list_empty(&n->poll_list))) { + pr_warn_once("%s: Budget exhausted after napi rescheduled\n", + n->dev ? n->dev->name : "backlog"); +- goto out_unlock; ++ return work; + } + +- list_add_tail(&n->poll_list, repoll); ++ *repoll = true; ++ ++ return work; ++} ++ ++static int napi_poll(struct napi_struct *n, struct list_head *repoll) ++{ ++ bool do_repoll = false; ++ void *have; ++ int work; ++ ++ list_del_init(&n->poll_list); ++ ++ have = netpoll_poll_lock(n); ++ ++ work = __napi_poll(n, &do_repoll); ++ ++ if (do_repoll) ++ list_add_tail(&n->poll_list, repoll); + +-out_unlock: + netpoll_poll_unlock(have); + + return work; diff --git a/feeds/ipq807x/ipq807x/patches/211-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch b/feeds/ipq807x/ipq807x/patches/211-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch new file mode 100644 index 000000000..e1268d96b --- /dev/null +++ b/feeds/ipq807x/ipq807x/patches/211-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch @@ -0,0 +1,245 @@ +From: Wei Wang +Date: Mon, 8 Feb 2021 11:34:09 -0800 +Subject: [PATCH] net: implement threaded-able napi poll loop support + +This patch allows running each napi poll loop inside its own +kernel thread. +The kthread is created during netif_napi_add() if dev->threaded +is set. And threaded mode is enabled in napi_enable(). We will +provide a way to set dev->threaded and enable threaded mode +without a device up/down in the following patch. + +Once that threaded mode is enabled and the kthread is +started, napi_schedule() will wake-up such thread instead +of scheduling the softirq. + +The threaded poll loop behaves quite likely the net_rx_action, +but it does not have to manipulate local irqs and uses +an explicit scheduling point based on netdev_budget. + +Co-developed-by: Paolo Abeni +Signed-off-by: Paolo Abeni +Co-developed-by: Hannes Frederic Sowa +Signed-off-by: Hannes Frederic Sowa +Co-developed-by: Jakub Kicinski +Signed-off-by: Jakub Kicinski +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -319,6 +319,7 @@ struct napi_struct { + struct list_head dev_list; + struct hlist_node napi_hash_node; + unsigned int napi_id; ++ struct task_struct *thread; + }; + + enum { +@@ -326,6 +327,7 @@ enum { + NAPI_STATE_DISABLE, /* Disable pending */ + NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ + NAPI_STATE_HASHED, /* In NAPI hash */ ++ NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ + }; + + enum gro_result { +@@ -501,13 +503,7 @@ void napi_disable(struct napi_struct *n) + * Resume NAPI from being scheduled on this context. + * Must be paired with napi_disable. + */ +-static inline void napi_enable(struct napi_struct *n) +-{ +- BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); +- smp_mb__before_atomic(); +- clear_bit(NAPI_STATE_SCHED, &n->state); +- clear_bit(NAPI_STATE_NPSVC, &n->state); +-} ++void napi_enable(struct napi_struct *n); + + /** + * napi_synchronize - wait until NAPI is not running +@@ -1573,6 +1569,8 @@ enum netdev_priv_flags_ext { + * switch driver and used to set the phys state of the + * switch port. + * ++ * @threaded: napi threaded mode is enabled ++ * + * FIXME: cleanup struct net_device such that network protocol info + * moves out. + */ +@@ -1852,6 +1850,7 @@ struct net_device { + struct phy_device *phydev; + struct lock_class_key *qdisc_tx_busylock; + bool proto_down; ++ unsigned threaded:1; + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -94,6 +94,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1304,6 +1305,27 @@ void netdev_notify_peers(struct net_devi + } + EXPORT_SYMBOL(netdev_notify_peers); + ++static int napi_threaded_poll(void *data); ++ ++static int napi_kthread_create(struct napi_struct *n) ++{ ++ int err = 0; ++ ++ /* Create and wake up the kthread once to put it in ++ * TASK_INTERRUPTIBLE mode to avoid the blocked task ++ * warning and work with loadavg. ++ */ ++ n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d", ++ n->dev->name, n->napi_id); ++ if (IS_ERR(n->thread)) { ++ err = PTR_ERR(n->thread); ++ pr_err("kthread_run failed with err %d\n", err); ++ n->thread = NULL; ++ } ++ ++ return err; ++} ++ + static int __dev_open(struct net_device *dev) + { + const struct net_device_ops *ops = dev->netdev_ops; +@@ -3248,6 +3270,21 @@ int weight_p __read_mostly = 64; + static inline void ____napi_schedule(struct softnet_data *sd, + struct napi_struct *napi) + { ++ struct task_struct *thread; ++ ++ if (test_bit(NAPI_STATE_THREADED, &napi->state)) { ++ /* Paired with smp_mb__before_atomic() in ++ * napi_enable(). Use READ_ONCE() to guarantee ++ * a complete read on napi->thread. Only call ++ * wake_up_process() when it's not NULL. ++ */ ++ thread = READ_ONCE(napi->thread); ++ if (thread) { ++ wake_up_process(thread); ++ return; ++ } ++ } ++ + list_add_tail(&napi->poll_list, &sd->poll_list); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + } +@@ -4828,9 +4865,33 @@ void netif_napi_add(struct net_device *d + napi->poll_owner = -1; + #endif + set_bit(NAPI_STATE_SCHED, &napi->state); ++ /* Create kthread for this napi if dev->threaded is set. ++ * Clear dev->threaded if kthread creation failed so that ++ * threaded mode will not be enabled in napi_enable(). ++ */ ++ if (dev->threaded && napi_kthread_create(napi)) ++ dev->threaded = 0; + } + EXPORT_SYMBOL(netif_napi_add); + ++/** ++ * napi_enable - enable NAPI scheduling ++ * @n: NAPI context ++ * ++ * Resume NAPI from being scheduled on this context. ++ * Must be paired with napi_disable. ++ */ ++void napi_enable(struct napi_struct *n) ++{ ++ BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); ++ smp_mb__before_atomic(); ++ clear_bit(NAPI_STATE_SCHED, &n->state); ++ clear_bit(NAPI_STATE_NPSVC, &n->state); ++ if (n->dev->threaded && n->thread) ++ set_bit(NAPI_STATE_THREADED, &n->state); ++} ++EXPORT_SYMBOL(napi_enable); ++ + void napi_disable(struct napi_struct *n) + { + might_sleep(); +@@ -4844,6 +4905,7 @@ void napi_disable(struct napi_struct *n) + hrtimer_cancel(&n->timer); + + clear_bit(NAPI_STATE_DISABLE, &n->state); ++ clear_bit(NAPI_STATE_THREADED, &n->state); + } + EXPORT_SYMBOL(napi_disable); + +@@ -4855,6 +4917,11 @@ void netif_napi_del(struct napi_struct * + kfree_skb_list(napi->gro_list); + napi->gro_list = NULL; + napi->gro_count = 0; ++ ++ if (napi->thread) { ++ kthread_stop(napi->thread); ++ napi->thread = NULL; ++ } + } + EXPORT_SYMBOL(netif_napi_del); + +@@ -4940,6 +5007,50 @@ static int napi_poll(struct napi_struct + return work; + } + ++static int napi_thread_wait(struct napi_struct *napi) ++{ ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!kthread_should_stop() && !napi_disable_pending(napi)) { ++ if (test_bit(NAPI_STATE_SCHED, &napi->state)) { ++ WARN_ON(!list_empty(&napi->poll_list)); ++ __set_current_state(TASK_RUNNING); ++ return 0; ++ } ++ ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++ return -1; ++} ++ ++static int napi_threaded_poll(void *data) ++{ ++ struct napi_struct *napi = data; ++ void *have; ++ ++ while (!napi_thread_wait(napi)) { ++ for (;;) { ++ bool repoll = false; ++ ++ local_bh_disable(); ++ ++ have = netpoll_poll_lock(napi); ++ __napi_poll(napi, &repoll); ++ netpoll_poll_unlock(have); ++ ++ local_bh_enable(); ++ ++ if (!repoll) ++ break; ++ ++ cond_resched(); ++ } ++ } ++ return 0; ++} ++ + static void net_rx_action(struct softirq_action *h) + { + struct softnet_data *sd = this_cpu_ptr(&softnet_data); diff --git a/feeds/ipq807x/ipq807x/patches/212-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch b/feeds/ipq807x/ipq807x/patches/212-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch new file mode 100644 index 000000000..5db5c8171 --- /dev/null +++ b/feeds/ipq807x/ipq807x/patches/212-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch @@ -0,0 +1,156 @@ +From: Wei Wang +Date: Mon, 8 Feb 2021 11:34:10 -0800 +Subject: [PATCH] net: add sysfs attribute to control napi threaded mode + +This patch adds a new sysfs attribute to the network device class. +Said attribute provides a per-device control to enable/disable the +threaded mode for all the napi instances of the given network device, +without the need for a device up/down. +User sets it to 1 or 0 to enable or disable threaded mode. +Note: when switching between threaded and the current softirq based mode +for a napi instance, it will not immediately take effect if the napi is +currently being polled. The mode switch will happen for the next time +napi_schedule() is called. + +Co-developed-by: Paolo Abeni +Signed-off-by: Paolo Abeni +Co-developed-by: Hannes Frederic Sowa +Signed-off-by: Hannes Frederic Sowa +Co-developed-by: Felix Fietkau +Signed-off-by: Felix Fietkau +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -496,6 +496,8 @@ void napi_hash_del(struct napi_struct *n + */ + void napi_disable(struct napi_struct *n); + ++int dev_set_threaded(struct net_device *dev, bool threaded); ++ + /** + * napi_enable - enable NAPI scheduling + * @n: napi context +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3274,8 +3274,9 @@ static inline void ____napi_schedule(str + + if (test_bit(NAPI_STATE_THREADED, &napi->state)) { + /* Paired with smp_mb__before_atomic() in +- * napi_enable(). Use READ_ONCE() to guarantee +- * a complete read on napi->thread. Only call ++ * napi_enable()/dev_set_threaded(). ++ * Use READ_ONCE() to guarantee a complete ++ * read on napi->thread. Only call + * wake_up_process() when it's not NULL. + */ + thread = READ_ONCE(napi->thread); +@@ -4844,6 +4845,49 @@ static enum hrtimer_restart napi_watchdo + return HRTIMER_NORESTART; + } + ++int dev_set_threaded(struct net_device *dev, bool threaded) ++{ ++ struct napi_struct *napi; ++ int err = 0; ++ ++ if (dev->threaded == threaded) ++ return 0; ++ ++ if (threaded) { ++ list_for_each_entry(napi, &dev->napi_list, dev_list) { ++ if (!napi->thread) { ++ err = napi_kthread_create(napi); ++ if (err) { ++ threaded = false; ++ break; ++ } ++ } ++ } ++ } ++ ++ dev->threaded = threaded; ++ ++ /* Make sure kthread is created before THREADED bit ++ * is set. ++ */ ++ smp_mb__before_atomic(); ++ ++ /* Setting/unsetting threaded mode on a napi might not immediately ++ * take effect, if the current napi instance is actively being ++ * polled. In this case, the switch between threaded mode and ++ * softirq mode will happen in the next round of napi_schedule(). ++ * This should not cause hiccups/stalls to the live traffic. ++ */ ++ list_for_each_entry(napi, &dev->napi_list, dev_list) { ++ if (threaded) ++ set_bit(NAPI_STATE_THREADED, &napi->state); ++ else ++ clear_bit(NAPI_STATE_THREADED, &napi->state); ++ } ++ ++ return err; ++} ++ + void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) + { +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -486,6 +486,45 @@ static ssize_t phys_switch_id_show(struc + } + static DEVICE_ATTR_RO(phys_switch_id); + ++static ssize_t threaded_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct net_device *netdev = to_net_dev(dev); ++ ssize_t ret = -EINVAL; ++ ++ if (!rtnl_trylock()) ++ return restart_syscall(); ++ ++ if (dev_isalive(netdev)) ++ ret = sprintf(buf, fmt_dec, netdev->threaded); ++ ++ rtnl_unlock(); ++ return ret; ++} ++ ++static int modify_napi_threaded(struct net_device *dev, unsigned long val) ++{ ++ int ret; ++ ++ if (list_empty(&dev->napi_list)) ++ return -EOPNOTSUPP; ++ ++ if (val != 0 && val != 1) ++ return -EOPNOTSUPP; ++ ++ ret = dev_set_threaded(dev, val); ++ ++ return ret; ++} ++ ++static ssize_t threaded_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return netdev_store(dev, attr, buf, len, modify_napi_threaded); ++} ++static DEVICE_ATTR_RW(threaded); ++ + static struct attribute *net_class_attrs[] = { + &dev_attr_netdev_group.attr, + &dev_attr_type.attr, +@@ -514,6 +553,7 @@ static struct attribute *net_class_attrs + &dev_attr_phys_port_name.attr, + &dev_attr_phys_switch_id.attr, + &dev_attr_proto_down.attr, ++ &dev_attr_threaded.attr, + NULL, + }; + ATTRIBUTE_GROUPS(net_class); diff --git a/feeds/ipq807x/ipq807x/patches/213-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch b/feeds/ipq807x/ipq807x/patches/213-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch new file mode 100644 index 000000000..2071c3903 --- /dev/null +++ b/feeds/ipq807x/ipq807x/patches/213-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch @@ -0,0 +1,75 @@ +From: Wei Wang +Date: Mon, 1 Mar 2021 17:21:13 -0800 +Subject: [PATCH] net: fix race between napi kthread mode and busy poll + +Currently, napi_thread_wait() checks for NAPI_STATE_SCHED bit to +determine if the kthread owns this napi and could call napi->poll() on +it. However, if socket busy poll is enabled, it is possible that the +busy poll thread grabs this SCHED bit (after the previous napi->poll() +invokes napi_complete_done() and clears SCHED bit) and tries to poll +on the same napi. napi_disable() could grab the SCHED bit as well. +This patch tries to fix this race by adding a new bit +NAPI_STATE_SCHED_THREADED in napi->state. This bit gets set in +____napi_schedule() if the threaded mode is enabled, and gets cleared +in napi_complete_done(), and we only poll the napi in kthread if this +bit is set. This helps distinguish the ownership of the napi between +kthread and other scenarios and fixes the race issue. + +Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") +Reported-by: Martin Zaharinov +Suggested-by: Jakub Kicinski +Signed-off-by: Wei Wang +Cc: Alexander Duyck +Cc: Eric Dumazet +Cc: Paolo Abeni +Cc: Hannes Frederic Sowa +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -328,6 +328,7 @@ enum { + NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ + NAPI_STATE_HASHED, /* In NAPI hash */ + NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ ++ NAPI_STATE_SCHED_THREADED, /* Napi is currently scheduled in threaded mode */ + }; + + enum gro_result { +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3281,6 +3281,8 @@ static inline void ____napi_schedule(str + */ + thread = READ_ONCE(napi->thread); + if (thread) { ++ if (thread->state != TASK_INTERRUPTIBLE) ++ set_bit(NAPI_STATE_SCHED_THREADED, &napi->state); + wake_up_process(thread); + return; + } +@@ -5053,16 +5055,25 @@ static int napi_poll(struct napi_struct + + static int napi_thread_wait(struct napi_struct *napi) + { ++ bool woken = false; ++ + set_current_state(TASK_INTERRUPTIBLE); + + while (!kthread_should_stop() && !napi_disable_pending(napi)) { +- if (test_bit(NAPI_STATE_SCHED, &napi->state)) { ++ /* Testing SCHED_THREADED bit here to make sure the current ++ * kthread owns this napi and could poll on this napi. ++ * Testing SCHED bit is not enough because SCHED bit might be ++ * set by some other busy poll thread or by napi_disable(). ++ */ ++ if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) { + WARN_ON(!list_empty(&napi->poll_list)); + __set_current_state(TASK_RUNNING); + return 0; + } + + schedule(); ++ /* woken being true indicates this thread owns this napi. */ ++ woken = true; + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); diff --git a/feeds/ipq807x/ipq807x/patches/214-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch b/feeds/ipq807x/ipq807x/patches/214-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch new file mode 100644 index 000000000..c4b28c49e --- /dev/null +++ b/feeds/ipq807x/ipq807x/patches/214-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch @@ -0,0 +1,53 @@ +From: Paolo Abeni +Date: Fri, 9 Apr 2021 17:24:17 +0200 +Subject: [PATCH] net: fix hangup on napi_disable for threaded napi + +napi_disable() is subject to an hangup, when the threaded +mode is enabled and the napi is under heavy traffic. + +If the relevant napi has been scheduled and the napi_disable() +kicks in before the next napi_threaded_wait() completes - so +that the latter quits due to the napi_disable_pending() condition, +the existing code leaves the NAPI_STATE_SCHED bit set and the +napi_disable() loop waiting for such bit will hang. + +This patch addresses the issue by dropping the NAPI_STATE_DISABLE +bit test in napi_thread_wait(). The later napi_threaded_poll() +iteration will take care of clearing the NAPI_STATE_SCHED. + +This also addresses a related problem reported by Jakub: +before this patch a napi_disable()/napi_enable() pair killed +the napi thread, effectively disabling the threaded mode. +On the patched kernel napi_disable() simply stops scheduling +the relevant thread. + +v1 -> v2: + - let the main napi_thread_poll() loop clear the SCHED bit + +Reported-by: Jakub Kicinski +Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") +Signed-off-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +--- + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -5059,7 +5059,7 @@ static int napi_thread_wait(struct napi_ + + set_current_state(TASK_INTERRUPTIBLE); + +- while (!kthread_should_stop() && !napi_disable_pending(napi)) { ++ while (!kthread_should_stop()) { + /* Testing SCHED_THREADED bit here to make sure the current + * kthread owns this napi and could poll on this napi. + * Testing SCHED bit is not enough because SCHED bit might be +@@ -5077,6 +5077,7 @@ static int napi_thread_wait(struct napi_ + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); ++ + return -1; + } + diff --git a/feeds/wifi-ax/mac80211/patches/pending/214-no-encap.patch b/feeds/wifi-ax/mac80211/patches/pending/214-no-encap.patch deleted file mode 100644 index 83259cae8..000000000 --- a/feeds/wifi-ax/mac80211/patches/pending/214-no-encap.patch +++ /dev/null @@ -1,21 +0,0 @@ -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/mac.c -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c -@@ -6590,6 +6590,7 @@ static int ath11k_mac_op_update_vif_offl - u32 param_id, param_value; - int ret; - -+ return 0; - if (ab->nss.enabled && vif->type == NL80211_IFTYPE_AP_VLAN) - return 0; - -@@ -6835,6 +6836,8 @@ static int ath11k_mac_op_add_interface(s - else - param_value = ATH11K_HW_TXRX_NATIVE_WIFI; - -+ param_value = ATH11K_HW_TXRX_NATIVE_WIFI; -+ - ret = ath11k_nss_vdev_set_cmd(arvif, NSS_WIFI_VDEV_ENCAP_TYPE_CMD, param_value); - - if(ret) { diff --git a/feeds/wifi-ax/mac80211/patches/pending/220-napi_threaded.patch b/feeds/wifi-ax/mac80211/patches/pending/220-napi_threaded.patch new file mode 100644 index 000000000..9b750c9cc --- /dev/null +++ b/feeds/wifi-ax/mac80211/patches/pending/220-napi_threaded.patch @@ -0,0 +1,57 @@ +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -526,6 +526,7 @@ static int ath11k_ahb_ext_irq_config(str + int irq; + int ret; + bool nss_offload; ++ static int devidx = 0; + + /* TCL Completion, REO Dest, ERR, Exception and h2rxdma rings are offloaded + * to nss when its enabled, hence don't enable these interrupts +@@ -539,6 +540,9 @@ static int ath11k_ahb_ext_irq_config(str + irq_grp->ab = ab; + irq_grp->grp_id = i; + init_dummy_netdev(&irq_grp->napi_ndev); ++ snprintf(irq_grp->napi_ndev.name, sizeof(irq_grp->napi_ndev.name), "%s%d:%d", ++ "ath11k_ahb", devidx, i); ++ irq_grp->napi_ndev.threaded = 1; + netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT); + +@@ -604,6 +608,8 @@ static int ath11k_ahb_ext_irq_config(str + } + } + ++ devidx++; ++ + return 0; + } + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -806,6 +806,7 @@ static int ath11k_pci_ext_irq_config(str + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0, base_idx; + u8 domain_id; ++ static int devidx = 0; + + domain_id = ath11k_pci_get_domain_id(ab); + base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; +@@ -822,6 +823,9 @@ static int ath11k_pci_ext_irq_config(str + irq_grp->ab = ab; + irq_grp->grp_id = i; + init_dummy_netdev(&irq_grp->napi_ndev); ++ snprintf(irq_grp->napi_ndev.name, sizeof(irq_grp->napi_ndev.name), "%s%d:%d", ++ "ath11k_pci", devidx, i); ++ irq_grp->napi_ndev.threaded = 1; + netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); + +@@ -868,6 +872,7 @@ static int ath11k_pci_ext_irq_config(str + } + } + ++ devidx++; + return 0; + } +