1
1
Files
zyxel-vmg8825_b50b-cfw/package/base-files-prebuild/files/rootfs/bin/wlaffinity
T
2026-04-17 18:33:03 +02:00

799 lines
21 KiB
Bash
Executable File

#!/bin/sh
# This script configures interrupt & thread affinity regarding to WLAN.
#
MAX_WLAN_ADAPTER=4
NUM_PROCESSOR=`cat /proc/cpuinfo | grep -c "processor"`
NUM_WL_INTF=`ls -al /sys/class/net/wl* 2>&1 | grep -c "wl. "`
#$(getStrByPos "12 33 44" " " 2) will return 33
getStrByPos() {
local num=$3;
IFS="$2"
set -- $1
eval result='$'$num;
echo $result;
}
getPidByName()
{
local pid=$(getStrByPos "`ps | grep -v grep | grep $1`" " " 1);
if [ -z $pid ]; then
echo 0;
else
echo $pid;
fi
}
#trim leading and trailing space
trim() {
if [ ! -z $* ]; then
local var="$*"
var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
fi
}
#change bitmask number to string mark of bit postion string
getBitmaskStr() {
local affinity=$((0x$1));
local cpu cpu_mask cpus="";
local cpu=0;
if [ ! -z $affinity ]; then
while [ ${cpu} -lt ${NUM_PROCESSOR} ];
do
cpu_mask=$((1 << $cpu))
if [ $((affinity&cpu_mask)) -gt 0 ]; then
if [ "$cpus" = "" ]; then
cpus=$cpu
else
cpus=$cpus"-$cpu"
fi
fi
cpu=$((cpu+1));
done
fi
echo $cpus;
}
process_name()
{
local radio=$2;
case "$1" in
wl)
echo "wl${radio}-kthrd"
;;
dhd)
echo "dhd${radio}_dpc";
;;
wfd)
echo "wfd${radio}-thrd";
;;
events)
echo "events/${radio}";
;;
esac
}
#get radio interupt with inputted radio number :0/1/2
getRadioInterrupt() {
local interrupt_line=`cat /proc/interrupts |grep "wl$1"`
if [ ! -z "$interrupt_line" ]; then
interrupt=$(getStrByPos "${interrupt_line}" ":" 1)
echo $(trim $interrupt);
fi
}
getRadioIntAffinity() {
local interrupt=$(getRadioInterrupt $1);
if [ ! -z $interrupt ]; then
local affinity="/proc/irq/$interrupt/smp_affinity";
echo `cat $affinity 2>/dev/NULL`
fi
}
getPidAffinityNum() {
echo $(getStrByPos "`taskset -p $1`" " " 6);
}
getPidAffinity() {
local pid=$1;
echo $(getBitmaskStr $(getPidAffinityNum $pid));
}
getPidPriority() {
echo $(getStrByPos "`chrt -p $1 | grep priority`" " " 6)
}
setProcPriority() {
local nvram_name=$1
local proc_name=$2
local pid=$3
local prio=$4
echo "set $proc_name and pid:$pid to prio:$prio"
chrt -p $prio $pid> /dev/null 2>&1
if [ "$?" != "0" ]; then
echo "Failed to set $proc_name to realtime priority $prio"
fi
#nvram kset $nvram_name=$prio;
}
setProcAffinity() {
local nvram_name=$1
local proc_name=$2
local pid=$3
local affinity=$4
echo "set $proc_name $pid to aff:$affinity"
taskset -p $affinity $pid> /dev/null 2>&1
if [ "$?" != "0" ]; then
echo "pin $proc_name failed, rc=$?, pid_wl0=$pid"
fi
#nvram kset $nvram_name=$affinity
}
procss_list()
{
local radio=0;
local title="$1 |";
local affinity="";
local priority=0;
while [ $radio -lt $NUM_WL_INTF ];
do
if [ $1 == "Process" ]; then
title="$title wl$radio(PID:CPUS:PRIO) |"
else
proc_name=$(process_name $1 $radio)
pid_wfd=$(getPidByName ${proc_name})
if [ $pid_wfd -gt 0 ]; then
affinity=$(getPidAffinity $pid_wfd)
priority=$(getPidPriority $pid_wfd)
title="$title $pid_wfd:$affinity:$priority |"
else
title="$title - |"
fi
fi
radio=`expr $radio + 1`
done
echo "${title}"
}
#### command shows the affinity ######
list_interrupt_affinity() {
local interrupt=0;
local affinity=0;
local radio=0;
title="Interrupt |";
while [ $radio -lt $NUM_WL_INTF ];
do
interrupt=$(getRadioInterrupt $radio)
if [ ! -z $interrupt ]; then
interrpt="int:"$(getRadioInterrupt $radio)
affinity="cpu:"$(getBitmaskStr $(getRadioIntAffinity $radio))
title="$title $interrpt($affinity) |";
else
title="$title - |"
fi
radio=`expr $radio + 1`
done
echo "$title";
}
list_nvram_settings() {
local affinity radio proc_name proc_pid prio name;
for ctl_item in wfd dhd wl
do
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
name="wl${radio}_${ctl_item}_affinity"
affinity=`nvram kget ${name}`;
if [ ! -z ${affinity} ]; then
echo $name=$affinity;
else
echo "$name is not defined, use default";
fi
name="wl${radio}_${ctl_item}_prio"
prio=`nvram kget ${name}`;
if [ ! -z ${prio} ]; then
echo $name=$prio;
else
echo "$name is not defined, use default";
fi
fi
radio=$((radio+1))
done
done
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_interrupt_affinity"
affinity=`nvram kget ${name}`;
if [ ! -z $affinity ]; then
echo "$name=$affinity";
else
echo "$name is not defined,use default";
fi
radio=$((radio+1))
done
}
list_wifi_process()
{
echo ""
echo " WiFi Processes on System (Total CPU:${NUM_PROCESSOR}) ";
echo "-------------------------------------------------------------------------";
procss_list "Process ";
echo "-------------------------------------------------------------------------";
procss_list "wfd ";
procss_list "dhd ";
procss_list "wl ";
echo "-------------------------------------------------------------------------";
list_interrupt_affinity;
echo "-------------------------------------------------------------------------";
echo ""
}
### command set #####
setRadioIntAffinity() {
local radio=$1;
local affinity=$2;
local irq=$(getRadioInterrupt $radio);
if [ ! -z $affinity ]; then
echo $affinity >/proc/irq/$irq/smp_affinity 2>/dev/NULL
#nvram kset wl${radio}_interrupt_affinity=${affinity}
fi
}
pin_wifi_processes()
{
local radio=0;
local num_wl_toconf=$NUM_WL_INTF;
local prompt proc_name prio_nvram_name affi_nvram_name;
if [ ! -z $1 ]; then
radio=$1;
num_wl_toconf=$((radio+1))
prompt="Config WiFi Radio $radio's Threads onto CPUs";
else
prompt="Config WiFi Radios Threads onto CPUs";
fi
echo ""
echo "${prompt}(Total CPU:${NUM_PROCESSOR})"
echo "-------------------------------------------------------------------------";
while [ $radio -lt $num_wl_toconf ];
do
for ctl_item in wfd dhd wl;
do
proc_name=$(process_name $ctl_item $radio);
pid_wfd=$(getPidByName ${proc_name});
if [ $pid_wfd -gt 0 ]; then
local affinity=0
local cpu=0;
while [ ${cpu} -lt ${NUM_PROCESSOR} ];
do
echo "Pin $ctl_item on radio $radio ($proc_name) onto CPU${cpu}(y/n):"
read answer
if [ $answer == "y" ]; then
affinity=$((affinity|(1<<cpu)))
fi
cpu=$((cpu+1))
done
echo "Assign $ctl_item on radio $radio real time priority[1-99]:"
read priority;
echo "Sure to change it?(y/n)"
read answer;
if [ $answer == "y" ]; then
prio_nvram_name="wl${radio}_${ctl_item}_prio";
setProcPriority $prio_nvram_name $proc_name $pid_wfd $priority
affi_nvram_name="wl${radio}_${ctl_item}_affinity"
setProcAffinity $affi_nvram_name $proc_name $pid_wfd $affinity
fi
fi
done
radio=$((radio+1))
done
}
pin_wifi_interrupt()
{
local radio=0;
local num_wl_toconf=$NUM_WL_INTF;
local prompt cpu affinity;
if [ ! -z $1 ]; then
radio=$1;
num_wl_toconf=$((radio+1))
prompt="Config WiFi Radio $radio's Interrupt onto CPUs";
else
prompt="Config WiFi Radios Interrupt onto CPUs";
fi
echo ""
echo "${prompt}(Total CPU:${NUM_PROCESSOR})"
echo "-------------------------------------------------------------------------";
while [ $radio -lt $num_wl_toconf ];
do
affinity=0
cpu=0;
while [ ${cpu} -lt ${NUM_PROCESSOR} ];
do
echo "Assign wl$radio's interrupt(tasklet) onto CPU${cpu}(y/n):"
read answer
if [ $answer == "y" ]; then
affinity=$((affinity|(1<<cpu)))
fi
cpu=$((cpu+1))
done
echo "Sure to change it?(y/n)"
read answer;
if [ $answer == "y" ]; then
setRadioIntAffinity $radio $affinity;
fi
radio=$((radio+1))
done
}
save_wifi_pin_cfg() {
local to_save=0;
local affinity radio proc_name proc_pid prio name;
for ctl_item in wfd dhd wl
do
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
to_save=1;
affinity=$(getPidAffinityNum $proc_pid);
prio=$(getPidPriority $proc_pid);
name="wl${radio}_${ctl_item}_affinity"
nvram kset $name=$affinity
name="wl${radio}_${ctl_item}_prio"
nvram kset $name=$prio
fi
radio=$((radio+1))
done
done
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_interrupt_affinity"
affinity=$(getRadioIntAffinity $radio);
if [ ! -z $affinity ]; then
to_save=1;
nvram kset $name=$affinity;
fi
radio=$((radio+1))
done
if [ $to_save -gt 0 ]; then
nvram kcommit
else
echo "!There is nothing to save actually!"
fi
}
unset_wifi_pin_cfg() {
local radio name ctl_item;
for ctl_item in wfd dhd wl
do
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_${ctl_item}_affinity"
nvram kunset $name
name="wl${radio}_${ctl_item}_prio"
nvram kunset $name
radio=$((radio+1))
done
done
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_interrupt_affinity"
nvram kunset $name
radio=$((radio+1))
done
nvam kunset wlthread_pinned
nvram kcommit
}
save_config_default() {
local radio=0;
local irq name prio affinity proc_name proc_pid;
local KERNEL_NVRAM_FILE="/etc/wlan/kernel_nvram.setting";
mount -t ubifs ubi:rootfs_ubifs / -o remount,rw
for ctl_item in wfd dhd wl
do
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
name="wl${radio}_${ctl_item}_affinity"
affinity=`nvram kget ${name}`
if [ ! -z $affinity ]; then
echo $name=$affinity >> ${KERNEL_NVRAM_FILE}
fi
name="wl${radio}_${ctl_item}_prio"
prio=`nvram kget ${name}`
if [ ! -z $affinity ]; then
echo $name=$prio >>${KERNEL_NVRAM_FILE}
fi
fi
radio=$((radio+1))
done
done
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_interrupt_affinity"
affinity=`nvram kget ${name}`
if [ ! -z $affinity ]; then
echo $name=$affinity >> ${KERNEL_NVRAM_FILE}
fi
radio=$((radio+1))
done
mount -t ubifs ubi:rootfs_ubifs / -o remount,ro
}
apply_wifi_pin_cfg() {
local applied=0 radio=0;
local irq name prio affinity proc_name proc_pid;
for ctl_item in wfd dhd wl
do
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
name="wl${radio}_${ctl_item}_affinity"
affinity=`nvram kget ${name}`
if [ ! -z $affinity ]; then
applied=1;
setProcAffinity $name $proc_name $proc_pid $affinity
fi
name="wl${radio}_${ctl_item}_prio"
prio=`nvram kget ${name}`
if [ ! -z $prio ]; then
applied=1;
setProcPriority $name $proc_name $proc_pid $prio
fi
fi
radio=$((radio+1))
done
done
#apply interrupt(tasklet) affinity
radio=0;
while [ $radio -lt $NUM_WL_INTF ];
do
name="wl${radio}_interrupt_affinity"
affinity=`nvram kget ${name}`
if [ ! -z $affinity ]; then
applied=1;
setRadioIntAffinity $radio $affinity
fi
radio=$((radio+1))
done
#echo $applied;
if [ ! -z "$1" ]; then
eval $1=$applied
fi
}
set_default_affinity_plat1()
{
ps | grep -v "grep" | grep -e "wl.-kthrd" > /dev/null 2>&1
[ "$?" == "0" ] || exit 0;
local tp=0
cat /proc/version | grep "SMP" > /dev/null 2>&1
if [ "$?" == "0" ]; then
tp=1
fi
if [ $NUM_WL_INTF -ge 2 ]; then
wlctl -i wl0 tp_id 0
wlctl -i wl1 tp_id $tp
if [ $NUM_WL_INTF -eq 3 ]; then
wlctl -i wl2 tp_id 0
fi
elif [ $NUM_WL_INTF -eq 1 ]; then
for i in $(seq 0 $((MAX_WLAN_ADAPTER-1)))
do
intf="wl$i"
if [ "x`cat /sys/class/net/$intf/operstate 2>/dev/null`" != "xdown" ]; then
wlctl -i $intf tp_id $tp
break;
fi
done
fi
}
set_default_affinity_platFAP()
{
local ctl_item radio affinity
if [ $NUM_WL_INTF -ge 2 ]; then
radio=0
while [ $radio -lt $NUM_WL_INTF ];
do
# /* bind to CPU{x} */
affinity=$((1 << (radio%NUM_PROCESSOR)))
# echo "affinity=$affinity"
for ctl_item in wfd dhd wl
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
done
radio=$((radio+1))
done
elif [ $NUM_WL_INTF -eq 1 ]; then
radio=0
for ctl_item in dhd wl wfd
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
if [ "$ctl_item" == "dhd" ]; then
affinity=$((1 << 0)) # bind dhd0_dpc to CPU0
elif [ "$ctl_item" == "wl" ]; then
affinity=$((1 << 1)) # bind wl0-kthrd to CPU1
fi
setProcAffinity "" $proc_name $proc_pid $affinity
fi
done
fi
}
set_default_affinity_plat3()
{
local ctl_item radio affinity
radio=0
while [ $radio -lt $NUM_WL_INTF ];
do
# /* bind to CPU{x} */
affinity=$((1 << (radio%NUM_PROCESSOR)))
# echo "affinity=$affinity"
for ctl_item in wfd dhd wl
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
done
radio=$((radio+1))
done
}
set_default_affinity_platArcher63178()
{
local radio affinity
# /* bind bcm_archer_us to cpu#2 */
affinity=$((1 << 2))
proc_name=bcm_archer_us
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
# /* bind bcmsw_recycle to cpu#1 */
affinity=$((1 << 1))
proc_name=bcmsw_recycle
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
# /* bind bcm_archer_wlan to cpu#1 */
affinity=$((1 << 1))
proc_name=bcm_archer_wlan
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
radio=0
while [ $radio -lt $NUM_WL_INTF ];
do
# /* bind wl/dhd to cpu#1. */
affinity=$((1 << 1))
#echo "affinity=$affinity"
for ctl_item in dhd wl
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
done
setRadioIntAffinity $radio $affinity;
radio=$((radio+1))
done
}
set_default_affinity_platArcher47622()
{
local radio affinity
# /* bind bcm_archer_us to cpu#3 */
affinity=$((1 << 3))
proc_name=bcm_archer_us
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
radio=0
while [ $radio -lt $NUM_WL_INTF ];
do
# /* bind to CPU{x} */
affinity=$((1 << (radio%NUM_PROCESSOR)))
#echo "affinity=$affinity"
for ctl_item in dhd wl
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcAffinity "" $proc_name $proc_pid $affinity
fi
done
setRadioIntAffinity $radio $affinity;
radio=$((radio+1))
done
}
set_default_priority()
{
local ctl_item radio priority
radio=0
priority=5
while [ $radio -lt $NUM_WL_INTF ];
do
for ctl_item in wfd wl
do
proc_name=$(process_name $ctl_item $radio);
proc_pid=$(getPidByName $proc_name);
if [ $proc_pid -gt 0 ]; then
setProcPriority "" $proc_name $proc_pid $priority
fi
done
radio=$((radio+1))
done
}
# configuring with default policy
pin_wifi_processes_default() {
local BCM_MODEL=`cat /proc/device-tree/model`
if [ -e /usr/sbin/escand ]; then
echo "Skip Wlan related processes pinning for EAP"
return
else
echo "Wlan related processes are pinned by default"
if [ $NUM_WL_INTF -gt 0 ]; then
if [ "$BCM_MODEL" == "Broadcom BCM963381" ]; then # Low end old platforms (no-fap, no-wfd)
set_default_affinity_plat1
elif [ "$BCM_MODEL" == "Broadcom BCM963268" ]; then # FAP based platforms
set_default_affinity_platFAP
elif [ "$BCM_MODEL" == "Broadcom BCM963178" ]; then # Archer based platforms with 3 cpu cores.
set_default_affinity_platArcher63178
elif [ "$BCM_MODEL" == "Broadcom BCM947622" ]; then # Archer based platforms with 4 cpu cores.
set_default_affinity_platArcher47622
else # High-end wfd based platforms
set_default_affinity_plat3
fi
# set priority
set_default_priority
fi
fi
}
auto_config() {
local apply_configed=0
echo "Configuring wlan related threads..."
apply_wifi_pin_cfg apply_configed
if [ $apply_configed -eq 0 ]; then
echo "no thread pin applied"
pin_wifi_processes_default
else
echo "Wlan related processes are pinned by configuration";
fi
}
# Check for arguments.
# User should give at least one argument to the program.
if [ $# -lt 1 ]; then
echo "Usage: $0 operation ..."
echo " operation: show, set, unset, save, apply"
echo " [option]: nvram for show; default for save "
exit 64
fi
# Parse the first argument
case "$1" in
auto)
auto_config
exit 0
;;
unset)
unset_wifi_pin_cfg;
;;
set)
case "$2" in
interrupt)
pin_wifi_interrupt $3
;;
thread)
pin_wifi_processes $3
;;
*)
pin_wifi_interrupt
pin_wifi_processes
;;
esac
list_wifi_process
;;
save)
case "$2" in
asdefault)
echo "save config default";
save_config_default;
;;
*)
echo "save config nvram";
save_wifi_pin_cfg;
;;
esac
;;
apply)
apply_wifi_pin_cfg;
;;
show)
case "$2" in
nvram)
list_nvram_settings
;;
*)
list_wifi_process
;;
esac
;;
*)
echo "unrecognized option [$1]"
exit 1
;;
esac