From 305c7599e5fa400cf6221fd0a596dbd014529235 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 13 Jul 2026 11:07:26 +0200 Subject: [PATCH] qualcommax: pin EDMA processing to dedicated CPUs IPQ60xx and IPQ807x use threaded NAPI for EDMA. The NAPI threads inherit CPU0 affinity, and running both there can eventually starve the RX fill ring under sustained traffic. Add an IPQ60xx smp_affinity service and extend the existing IPQ807x service to discover the EDMA IRQs and NAPI IDs at runtime. Place RX on CPU1 and TX on CPU2. Retry EDMA setup asynchronously because its NAPI threads may appear after the init service runs. Provide the same UCI enable and logging controls on both subtargets. IPQ50xx uses a different Ethernet driver and is left unchanged. Link: https://github.com/openwrt/openwrt/pull/24203 Signed-off-by: Robert Marko --- .../base-files/etc/init.d/smp_affinity | 105 ++++++++++++++++++ .../etc/uci-defaults/15_smp_affinity | 11 ++ .../base-files/etc/init.d/smp_affinity | 72 +++++++++++- 3 files changed, 182 insertions(+), 6 deletions(-) create mode 100755 target/linux/qualcommax/ipq60xx/base-files/etc/init.d/smp_affinity create mode 100644 target/linux/qualcommax/ipq60xx/base-files/etc/uci-defaults/15_smp_affinity diff --git a/target/linux/qualcommax/ipq60xx/base-files/etc/init.d/smp_affinity b/target/linux/qualcommax/ipq60xx/base-files/etc/init.d/smp_affinity new file mode 100755 index 00000000000..45868e9aad2 --- /dev/null +++ b/target/linux/qualcommax/ipq60xx/base-files/etc/init.d/smp_affinity @@ -0,0 +1,105 @@ +#!/bin/sh /etc/rc.common + +START=94 + +PROG=smp_affinity + +log_msg() { + local type="$1" id="$2" name="$3" affinity="$4" + + logger -t "$PROG" "Pinning $type($id) $name to CPU $affinity" +} + +get_irq() { + awk -v name="$1" '$NF == name { + sub(/:$/, "", $1) + print $1 + exit + }' /proc/interrupts +} + +get_napi_threads() { + local comm comm_path id pid + + TX_NAPI_ID= + TX_PID= + RX_NAPI_ID= + RX_PID= + + for comm_path in /proc/[0-9]*/comm; do + read -r comm < "$comm_path" + case "$comm" in + napi/eth0-[0-9]*) + id="${comm##*-}" + pid="${comm_path#/proc/}" + pid="${pid%/comm}" + + if [ -z "$TX_NAPI_ID" ] || [ "$id" -lt "$TX_NAPI_ID" ]; then + TX_NAPI_ID="$id" + TX_PID="$pid" + fi + + if [ -z "$RX_NAPI_ID" ] || [ "$id" -gt "$RX_NAPI_ID" ]; then + RX_NAPI_ID="$id" + RX_PID="$pid" + fi + ;; + esac + done +} + +pin_irq() { + local irq="$1" mask="$2" affinity="$3" name="$4" + + [ -n "$irq" ] || return + $enable_log && log_msg IRQ "$irq" "$name" "$affinity" + echo "$mask" > "/proc/irq/$irq/smp_affinity" +} + +pin_thread() { + local pid="$1" mask="$2" affinity="$3" name="$4" + + [ -n "$pid" ] || return + $enable_log && log_msg thread "$pid" "$name" "$affinity" + taskset -p "$mask" "$pid" >/dev/null +} + +enable_affinity_edma() { + local seconds=0 rx_irq tx_irq + + while [ "$seconds" -lt 60 ]; do + rx_irq="$(get_irq edma_rxdesc)" + tx_irq="$(get_irq edma_txcmpl)" + get_napi_threads + + [ -n "$rx_irq" ] && [ -n "$tx_irq" ] && + [ -n "$RX_PID" ] && [ -n "$TX_PID" ] && + [ "$RX_PID" != "$TX_PID" ] && break + + seconds=$((seconds + 1)) + sleep 1 + done + + [ -n "$rx_irq" ] && [ -n "$tx_irq" ] && + [ -n "$RX_PID" ] && [ -n "$TX_PID" ] && + [ "$RX_PID" != "$TX_PID" ] || return + + pin_irq "$rx_irq" 2 1 edma_rxdesc + pin_thread "$RX_PID" 2 1 "EDMA RX NAPI" + pin_irq "$tx_irq" 4 2 edma_txcmpl + pin_thread "$TX_PID" 4 2 "EDMA TX NAPI" +} + +boot() { + local enable + + config_load smp_affinity + + config_get_bool enable "general" enable 1 + config_get_bool enable_log "general" enable_log 1 + + [ "$enable" -eq 1 ] && enable=true || enable=false + [ "$enable_log" -eq 1 ] && enable_log=true || enable_log=false + + $enable && enable_affinity_edma & +} diff --git a/target/linux/qualcommax/ipq60xx/base-files/etc/uci-defaults/15_smp_affinity b/target/linux/qualcommax/ipq60xx/base-files/etc/uci-defaults/15_smp_affinity new file mode 100644 index 00000000000..3ec0adc44cd --- /dev/null +++ b/target/linux/qualcommax/ipq60xx/base-files/etc/uci-defaults/15_smp_affinity @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q get smp_affinity && exit 0 +touch /etc/config/smp_affinity + +uci -q batch << EOF + set smp_affinity.general=smp_affinity + set smp_affinity.general.enable='1' + set smp_affinity.general.enable_log='1' + commit smp_affinity +EOF diff --git a/target/linux/qualcommax/ipq807x/base-files/etc/init.d/smp_affinity b/target/linux/qualcommax/ipq807x/base-files/etc/init.d/smp_affinity index ecf88aea095..690a8cfa34f 100755 --- a/target/linux/qualcommax/ipq807x/base-files/etc/init.d/smp_affinity +++ b/target/linux/qualcommax/ipq807x/base-files/etc/init.d/smp_affinity @@ -81,6 +81,68 @@ set_affinity() { done } +get_napi_threads() { + + local comm comm_path id pid + + TX_NAPI_ID= + TX_PID= + RX_NAPI_ID= + RX_PID= + + for comm_path in /proc/[0-9]*/comm; do + read -r comm < "$comm_path" + case "$comm" in + napi/eth0-[0-9]*) + id="${comm##*-}" + pid="${comm_path#/proc/}" + pid="${pid%/comm}" + + if [ -z "$TX_NAPI_ID" ] || [ "$id" -lt "$TX_NAPI_ID" ]; then + TX_NAPI_ID="$id" + TX_PID="$pid" + fi + + if [ -z "$RX_NAPI_ID" ] || [ "$id" -gt "$RX_NAPI_ID" ]; then + RX_NAPI_ID="$id" + RX_PID="$pid" + fi + ;; + esac + done +} + +set_thread_affinity() { + + local pid="$1" affinity="$2" bitmask + + [ -n "$pid" ] || return + bitmask=$(cpus_to_bitmask "$affinity") && + taskset -p "$bitmask" "$pid" >/dev/null +} + +enable_affinity_edma() { + + local seconds=0 + + while [ "$seconds" -lt 60 ]; do + get_napi_threads + [ -n "$RX_PID" ] && [ -n "$TX_PID" ] && + [ "$RX_PID" != "$TX_PID" ] && break + + seconds=$((seconds + 1)) + sleep 1 + done + + [ -n "$RX_PID" ] && [ -n "$TX_PID" ] && + [ "$RX_PID" != "$TX_PID" ] || return + + set_affinity 'edma_rxdesc' 1 + set_thread_affinity "$RX_PID" 1 + set_affinity 'edma_txcmpl' 2 + set_thread_affinity "$TX_PID" 2 +} + enable_affinity_ipq807x() { # assign 4 rx interrupts to each core @@ -99,11 +161,6 @@ enable_affinity_ipq807x() { set_affinity 'ppdu-end-interrupts-mac2' 2 set_affinity 'ppdu-end-interrupts-mac3' 3 - # assign 4 lan/wan to core 4 - set_affinity 'edma_txcmpl' 3 - set_affinity 'edma_rxfill' 3 - set_affinity 'edma_rxdesc' 3 - set_affinity 'edma_misc' 3 } boot() { @@ -118,5 +175,8 @@ boot() { [ "$enable" -eq 1 ] && enable=true || enable=false [ "$enable_log" -eq 1 ] && enable_log=true || enable_log=false - $enable && enable_affinity_ipq807x + $enable && { + enable_affinity_ipq807x + enable_affinity_edma & + } } -- 2.47.3