xref: /linux/tools/testing/selftests/drivers/net/hw/ethtool.sh (revision b86761ff6374813cdf64ffd6b95ddd1813c435d8)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5	same_speeds_autoneg_off
6	different_speeds_autoneg_off
7	combination_of_neg_on_and_off
8	advertise_subset_of_speeds
9	check_highest_speed_is_chosen
10	different_speeds_autoneg_on
11"
12NUM_NETIFS=2
13lib_dir=$(dirname "$0")
14source "$lib_dir"/../../../net/forwarding/lib.sh
15source ethtool_lib.sh
16
17h1_create()
18{
19	simple_if_init $h1 192.0.2.1/24
20}
21
22h1_destroy()
23{
24	simple_if_fini $h1 192.0.2.1/24
25}
26
27h2_create()
28{
29	simple_if_init $h2 192.0.2.2/24
30}
31
32h2_destroy()
33{
34	simple_if_fini $h2 192.0.2.2/24
35}
36
37setup_prepare()
38{
39	h1=${NETIFS[p1]}
40	h2=${NETIFS[p2]}
41
42	h1_create
43	h2_create
44}
45
46cleanup()
47{
48	pre_cleanup
49
50	h2_destroy
51	h1_destroy
52}
53
54same_speeds_autoneg_off()
55{
56	# Check that when each of the reported speeds is forced, the links come
57	# up and are operational.
58	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 0))
59
60	for speed in "${speeds_arr[@]}"; do
61		RET=0
62		ethtool_set $h1 speed $speed autoneg off
63		ethtool_set $h2 speed $speed autoneg off
64
65		setup_wait_dev_with_timeout $h1
66		setup_wait_dev_with_timeout $h2
67		ping_do $h1 192.0.2.2
68		check_err $? "speed $speed autoneg off"
69		log_test "force of same speed autoneg off"
70		log_info "speed = $speed"
71	done
72
73	ethtool -s $h2 autoneg on
74	ethtool -s $h1 autoneg on
75}
76
77different_speeds_autoneg_off()
78{
79	# Test that when we force different speeds, links are not up and ping
80	# fails.
81	RET=0
82
83	local -a speeds_arr=($(different_speeds_get $h1 $h2 0 0))
84	local speed1=${speeds_arr[0]}
85	local speed2=${speeds_arr[1]}
86
87	ethtool_set $h1 speed $speed1 autoneg off
88	ethtool_set $h2 speed $speed2 autoneg off
89
90	setup_wait_dev_with_timeout $h1
91	setup_wait_dev_with_timeout $h2
92	ping_do $h1 192.0.2.2
93	check_fail $? "ping with different speeds"
94
95	log_test "force of different speeds autoneg off"
96
97	ethtool -s $h2 autoneg on
98	ethtool -s $h1 autoneg on
99}
100
101combination_of_neg_on_and_off()
102{
103	# Test that when one device is forced to a speed supported by both
104	# endpoints and the other device is configured to autoneg on, the links
105	# are up and ping passes.
106	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 1))
107
108	for speed in "${speeds_arr[@]}"; do
109		RET=0
110		ethtool_set $h1 speed $speed autoneg off
111
112		setup_wait_dev_with_timeout $h1
113		setup_wait_dev_with_timeout $h2
114		ping_do $h1 192.0.2.2
115		check_err $? "h1-speed=$speed autoneg off, h2 autoneg on"
116		log_test "one side with autoneg off and another with autoneg on"
117		log_info "force speed = $speed"
118	done
119
120	ethtool -s $h1 autoneg on
121}
122
123hex_speed_value_get()
124{
125	local speed=$1; shift
126
127	local shift_size=${speed_values[$speed]}
128	speed=$((0x1 << $"shift_size"))
129	printf "%#x" "$speed"
130}
131
132subset_of_common_speeds_get()
133{
134	local dev1=$1; shift
135	local dev2=$1; shift
136	local adver=$1; shift
137
138	local -a speeds_arr=($(common_speeds_get $dev1 $dev2 0 $adver))
139	local speed_to_advertise=0
140	local speed_to_remove=${speeds_arr[0]}
141	speed_to_remove+='base'
142
143	local -a speeds_mode_arr=($(common_speeds_get $dev1 $dev2 1 $adver))
144
145	for speed in ${speeds_mode_arr[@]}; do
146		if [[ $speed != $speed_to_remove* ]]; then
147			speed=$(hex_speed_value_get $speed)
148			speed_to_advertise=$(($speed_to_advertise | \
149						$speed))
150		fi
151
152	done
153
154	# Convert to hex.
155	printf "%#x" "$speed_to_advertise"
156}
157
158speed_to_advertise_get()
159{
160	# The function returns the hex number that is composed by OR-ing all
161	# the modes corresponding to the provided speed.
162	local speed_without_mode=$1; shift
163	local supported_speeds=("$@"); shift
164	local speed_to_advertise=0
165
166	speed_without_mode+='base'
167
168	for speed in ${supported_speeds[@]}; do
169		if [[ $speed == $speed_without_mode* ]]; then
170			speed=$(hex_speed_value_get $speed)
171			speed_to_advertise=$(($speed_to_advertise | \
172						$speed))
173		fi
174
175	done
176
177	# Convert to hex.
178	printf "%#x" "$speed_to_advertise"
179}
180
181advertise_subset_of_speeds()
182{
183	# Test that when one device advertises a subset of speeds and another
184	# advertises a specific speed (but all modes of this speed), the links
185	# are up and ping passes.
186	RET=0
187
188	local speed_1_to_advertise=$(subset_of_common_speeds_get $h1 $h2 1)
189	ethtool_set $h1 advertise $speed_1_to_advertise
190
191	if [ $RET != 0 ]; then
192		log_test "advertise subset of speeds"
193		return
194	fi
195
196	local -a speeds_arr_without_mode=($(common_speeds_get $h1 $h2 0 1))
197	# Check only speeds that h1 advertised. Remove the first speed.
198	unset speeds_arr_without_mode[0]
199	local -a speeds_arr_with_mode=($(common_speeds_get $h1 $h2 1 1))
200
201	for speed_value in ${speeds_arr_without_mode[@]}; do
202		RET=0
203		local speed_2_to_advertise=$(speed_to_advertise_get $speed_value \
204			"${speeds_arr_with_mode[@]}")
205		ethtool_set $h2 advertise $speed_2_to_advertise
206
207		setup_wait_dev_with_timeout $h1
208		setup_wait_dev_with_timeout $h2
209		ping_do $h1 192.0.2.2
210		check_err $? "h1=$speed_1_to_advertise, h2=$speed_2_to_advertise ($speed_value)"
211
212		log_test "advertise subset of speeds"
213		log_info "h1=$speed_1_to_advertise, h2=$speed_2_to_advertise"
214	done
215
216	ethtool -s $h2 autoneg on
217	ethtool -s $h1 autoneg on
218}
219
220check_highest_speed_is_chosen()
221{
222	# Test that when one device advertises a subset of speeds, the other
223	# chooses the highest speed. This test checks configuration without
224	# traffic.
225	RET=0
226
227	local max_speed
228	local chosen_speed
229	local speed_to_advertise=$(subset_of_common_speeds_get $h1 $h2 1)
230
231	ethtool_set $h1 advertise $speed_to_advertise
232
233	if [ $RET != 0 ]; then
234		log_test "check highest speed"
235		return
236	fi
237
238	local -a speeds_arr=($(common_speeds_get $h1 $h2 0 1))
239
240	max_speed=${speeds_arr[0]}
241	for current in ${speeds_arr[@]}; do
242		if [[ $current -gt $max_speed ]]; then
243			max_speed=$current
244		fi
245	done
246
247	setup_wait_dev_with_timeout $h1
248	setup_wait_dev_with_timeout $h2
249	chosen_speed=$(ethtool $h1 | grep 'Speed:')
250	chosen_speed=${chosen_speed%"Mb/s"*}
251	chosen_speed=${chosen_speed#*"Speed: "}
252	((chosen_speed == max_speed))
253	check_err $? "h1 advertise $speed_to_advertise, h2 sync to speed $chosen_speed"
254
255	log_test "check highest speed"
256
257	ethtool -s $h2 autoneg on
258	ethtool -s $h1 autoneg on
259}
260
261different_speeds_autoneg_on()
262{
263	# Test that when we configure links to advertise different speeds,
264	# links are not up and ping fails.
265	RET=0
266
267	local -a speeds=($(different_speeds_get $h1 $h2 1 1))
268	local speed1=${speeds[0]}
269	local speed2=${speeds[1]}
270
271	speed1=$(hex_speed_value_get $speed1)
272	speed2=$(hex_speed_value_get $speed2)
273
274	ethtool_set $h1 advertise $speed1
275	ethtool_set $h2 advertise $speed2
276
277	if (($RET)); then
278		setup_wait_dev_with_timeout $h1
279		setup_wait_dev_with_timeout $h2
280		ping_do $h1 192.0.2.2
281		check_fail $? "ping with different speeds autoneg on"
282	fi
283
284	log_test "advertise different speeds autoneg on"
285
286	ethtool -s $h2 autoneg on
287	ethtool -s $h1 autoneg on
288}
289
290trap cleanup EXIT
291
292setup_prepare
293setup_wait
294
295declare -gA speed_values
296eval "speed_values=($(speeds_arr_get))"
297
298tests_run
299
300exit $EXIT_STATUS
301