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 <robimarko@gmail.com>
This commit is contained in:
Robert Marko
2026-07-13 11:07:26 +02:00
parent 98108710b6
commit 305c7599e5
3 changed files with 182 additions and 6 deletions
@@ -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 &
}
@@ -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
@@ -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 &
}
}