#! /bin/sh

#Copyright 2024 Hannes Diethelm <hannes.diethelm@gmail.com>

set -e
#set -x

#Can be integrated in /etc/network/interfaces the following way
#assuming your network card is enp2s0f0 and your realtime
#CPU is CPU3 (2^3 = 8 for the mask):
#auto enp2s0f0
#iface enp2s0f0 inet static
#  address 192.168.1.120/31
#  post-up /usr/local/sbin/eth-rt-affinity enp2s0f0 8

if [ "$#" -ne 3 ]; then
    echo "Usage: eth-rt-affinity nic1 mask nic2"
    exit 1
fi

NIC=$1
NIC2=$3
MASK=$2
#Priority 90 should be fine for most cases
#It should be lower than lowest linuxcnc task
RT_PRIO=90

echo These can fail if not supported by card---------
echo Setting coalesce
ethtool -C "$NIC" rx-usecs 1 tx-usecs 1 || true
ethtool -c "$NIC" || true

echo Setting queues
echo rx
ethtool -L "$NIC" rx 1 || true
echo tx
ethtool -L "$NIC" tx 1 || true
echo combined
ethtool -L "$NIC" combined 1 || true
ethtool -l "$NIC" || true

echo ------------------------------------------------

echo "Setting affinity for $NIC to use CPU Mask $MASK..."

# Set system-wide default affinity to exclude CPU 8
echo 7f > /proc/irq/default_smp_affinity  # 0x7f = CPUs 0,1,2,3,4,5,6 only
# New IRQs will be placed on CPUs 0,1,2,3,4,5,6 by default

RT_IRQS=$(grep "$NIC\|$NIC2" /proc/interrupts | awk -F: '{print $1}' | tr -d ' ')
OTHER_IRQS=$(grep -v "$NIC\|$NIC2" /proc/interrupts | awk -F: '{print $1}' | tr -d ' ')
if [ -z "$RT_IRQS" ]; then
    echo "Error: No IRQ's found for $NIC"
    exit 1
fi

echo $RT_IRQS
echo $OTHER_IRQS

for IRQ in $RT_IRQS; do
	PID=$(pgrep "irq/$IRQ" || true)
	if [ -z "$PID" ]; then
		echo "No process found for IRQ $IRQ, this is no issue if you use a kernel without PREEMT_RT patch"
	else
		echo "Setting pid $PID irq $IRQ process $(cat "/proc/$PID/comm") to use realtime priority $RT_PRIO"
		chrt -p "$RT_PRIO" "$PID"
		taskset -p "$MASK" "$PID"
	fi
	echo "Setting irq $IRQ to mask $MASK"
	echo "$MASK" > "/proc/irq/$IRQ/smp_affinity"
done

for IRQ in $OTHER_IRQS; do
	PID=$(pgrep "irq/$IRQ" || true)
	if [ -z "$PID" ]; then
		echo "No process found for IRQ $IRQ, this is no issue if you use a kernel without PREEMT_RT patch"
	else
		echo "Setting pid $PID irq $IRQ process $(cat "/proc/$PID/comm") to use realtime priority $RT_PRIO"
	fi
	echo "Setting irq $IRQ to mask $MASK"
	echo 7F > "/proc/irq/$IRQ/smp_affinity"
done

echo "done"
