#!/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<> ${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