1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# Copyright 2021-2022 NXP 4 5tc_testing_scripts_dir=$(dirname $0)/../../tc-testing/scripts 6 7REQUIRE_ISOCHRON=${REQUIRE_ISOCHRON:=yes} 8REQUIRE_LINUXPTP=${REQUIRE_LINUXPTP:=yes} 9 10# Tunables 11UTC_TAI_OFFSET=37 12ISOCHRON_CPU=1 13 14if [[ "$REQUIRE_ISOCHRON" = "yes" ]]; then 15 # https://github.com/vladimiroltean/tsn-scripts 16 # WARNING: isochron versions pre-1.0 are unstable, 17 # always use the latest version 18 require_command isochron 19fi 20if [[ "$REQUIRE_LINUXPTP" = "yes" ]]; then 21 require_command phc2sys 22 require_command ptp4l 23 require_command phc_ctl 24fi 25 26phc2sys_start() 27{ 28 local uds_address=$1 29 local extra_args="" 30 31 if ! [ -z "${uds_address}" ]; then 32 extra_args="${extra_args} -z ${uds_address}" 33 fi 34 35 phc2sys_log="$(mktemp)" 36 37 chrt -f 10 phc2sys -m \ 38 -a -rr \ 39 --step_threshold 0.00002 \ 40 --first_step_threshold 0.00002 \ 41 ${extra_args} \ 42 > "${phc2sys_log}" 2>&1 & 43 phc2sys_pid=$! 44 45 echo "phc2sys logs to ${phc2sys_log} and has pid ${phc2sys_pid}" 46 47 sleep 1 48} 49 50phc2sys_stop() 51{ 52 { kill ${phc2sys_pid} && wait ${phc2sys_pid}; } 2> /dev/null 53 rm "${phc2sys_log}" 2> /dev/null 54} 55 56# Replace space separators from interface list with underscores 57if_names_to_label() 58{ 59 local if_name_list="$1" 60 61 echo "${if_name_list/ /_}" 62} 63 64ptp4l_start() 65{ 66 local if_names="$1" 67 local slave_only=$2 68 local uds_address=$3 69 local log="ptp4l_log_$(if_names_to_label ${if_names})" 70 local pid="ptp4l_pid_$(if_names_to_label ${if_names})" 71 local extra_args="" 72 73 for if_name in ${if_names}; do 74 extra_args="${extra_args} -i ${if_name}" 75 done 76 77 if [ "${slave_only}" = true ]; then 78 extra_args="${extra_args} -s" 79 fi 80 81 # declare dynamic variables ptp4l_log_${if_name} and ptp4l_pid_${if_name} 82 # as global, so that they can be referenced later 83 declare -g "${log}=$(mktemp)" 84 85 chrt -f 10 ptp4l -m -2 -P \ 86 --step_threshold 0.00002 \ 87 --first_step_threshold 0.00002 \ 88 --tx_timestamp_timeout 100 \ 89 --uds_address="${uds_address}" \ 90 ${extra_args} \ 91 > "${!log}" 2>&1 & 92 declare -g "${pid}=$!" 93 94 echo "ptp4l for interfaces ${if_names} logs to ${!log} and has pid ${!pid}" 95 96 sleep 1 97} 98 99ptp4l_stop() 100{ 101 local if_names="$1" 102 local log="ptp4l_log_$(if_names_to_label ${if_names})" 103 local pid="ptp4l_pid_$(if_names_to_label ${if_names})" 104 105 { kill ${!pid} && wait ${!pid}; } 2> /dev/null 106 rm "${!log}" 2> /dev/null 107} 108 109cpufreq_max() 110{ 111 local cpu=$1 112 local freq="cpu${cpu}_freq" 113 local governor="cpu${cpu}_governor" 114 115 # Kernel may be compiled with CONFIG_CPU_FREQ disabled 116 if ! [ -d /sys/bus/cpu/devices/cpu${cpu}/cpufreq ]; then 117 return 118 fi 119 120 # declare dynamic variables cpu${cpu}_freq and cpu${cpu}_governor as 121 # global, so they can be referenced later 122 declare -g "${freq}=$(cat /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_min_freq)" 123 declare -g "${governor}=$(cat /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_governor)" 124 125 cat /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_max_freq > \ 126 /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_min_freq 127 echo -n "performance" > \ 128 /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_governor 129} 130 131cpufreq_restore() 132{ 133 local cpu=$1 134 local freq="cpu${cpu}_freq" 135 local governor="cpu${cpu}_governor" 136 137 if ! [ -d /sys/bus/cpu/devices/cpu${cpu}/cpufreq ]; then 138 return 139 fi 140 141 echo "${!freq}" > /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_min_freq 142 echo -n "${!governor}" > \ 143 /sys/bus/cpu/devices/cpu${cpu}/cpufreq/scaling_governor 144} 145 146isochron_recv_start() 147{ 148 local if_name=$1 149 local uds=$2 150 local stats_port=$3 151 local extra_args=$4 152 local pid="isochron_pid_${stats_port}" 153 154 if ! [ -z "${uds}" ]; then 155 extra_args="${extra_args} --unix-domain-socket ${uds}" 156 fi 157 158 isochron rcv \ 159 --interface ${if_name} \ 160 --sched-priority 98 \ 161 --sched-fifo \ 162 --utc-tai-offset ${UTC_TAI_OFFSET} \ 163 --stats-port ${stats_port} \ 164 --quiet \ 165 ${extra_args} & \ 166 declare -g "${pid}=$!" 167 168 sleep 1 169} 170 171isochron_recv_stop() 172{ 173 local stats_port=$1 174 local pid="isochron_pid_${stats_port}" 175 176 { kill ${!pid} && wait ${!pid}; } 2> /dev/null 177} 178 179isochron_do() 180{ 181 local sender_if_name=$1; shift 182 local receiver_if_name=$1; shift 183 local sender_uds=$1; shift 184 local receiver_uds=$1; shift 185 local base_time=$1; shift 186 local cycle_time=$1; shift 187 local shift_time=$1; shift 188 local window_size=$1; shift 189 local num_pkts=$1; shift 190 local vid=$1; shift 191 local priority=$1; shift 192 local dst_ip=$1; shift 193 local isochron_dat=$1; shift 194 local extra_args="" 195 local receiver_extra_args="" 196 local vrf="$(master_name_get ${sender_if_name})" 197 local use_l2="true" 198 199 if ! [ -z "${dst_ip}" ]; then 200 use_l2="false" 201 fi 202 203 if ! [ -z "${vrf}" ]; then 204 dst_ip="${dst_ip}%${vrf}" 205 fi 206 207 if ! [ -z "${vid}" ]; then 208 vid="--vid=${vid}" 209 fi 210 211 if [ -z "${receiver_uds}" ]; then 212 extra_args="${extra_args} --omit-remote-sync" 213 fi 214 215 if ! [ -z "${shift_time}" ]; then 216 extra_args="${extra_args} --shift-time=${shift_time}" 217 fi 218 219 if ! [ -z "${window_size}" ]; then 220 extra_args="${extra_args} --window-size=${window_size}" 221 fi 222 223 if [ "${use_l2}" = "true" ]; then 224 extra_args="${extra_args} --l2 --etype=0xdead ${vid}" 225 receiver_extra_args="--l2 --etype=0xdead" 226 else 227 extra_args="${extra_args} --l4 --ip-destination=${dst_ip}" 228 receiver_extra_args="--l4" 229 fi 230 231 cpufreq_max ${ISOCHRON_CPU} 232 233 isochron_recv_start "${h2}" "${receiver_uds}" 5000 "${receiver_extra_args}" 234 235 isochron send \ 236 --interface ${sender_if_name} \ 237 --unix-domain-socket ${sender_uds} \ 238 --priority ${priority} \ 239 --base-time ${base_time} \ 240 --cycle-time ${cycle_time} \ 241 --num-frames ${num_pkts} \ 242 --frame-size 64 \ 243 --txtime \ 244 --utc-tai-offset ${UTC_TAI_OFFSET} \ 245 --cpu-mask $((1 << ${ISOCHRON_CPU})) \ 246 --sched-fifo \ 247 --sched-priority 98 \ 248 --client 127.0.0.1 \ 249 --sync-threshold 5000 \ 250 --output-file ${isochron_dat} \ 251 ${extra_args} \ 252 --quiet 253 254 isochron_recv_stop 5000 255 256 cpufreq_restore ${ISOCHRON_CPU} 257} 258 259isochron_report_num_received() 260{ 261 local isochron_dat=$1; shift 262 263 # Count all received packets by looking at the non-zero RX timestamps 264 isochron report \ 265 --input-file "${isochron_dat}" \ 266 --printf-format "%u\n" --printf-args "R" | \ 267 grep -w -v '0' | wc -l 268} 269 270taprio_wait_for_admin() 271{ 272 local if_name="$1"; shift 273 274 "$tc_testing_scripts_dir/taprio_wait_for_admin.sh" "$(which tc)" "$if_name" 275} 276