1185646a8SJakub Kicinski#!/usr/bin/env python3 2185646a8SJakub Kicinski# SPDX-License-Identifier: GPL-2.0 3185646a8SJakub Kicinski 4185646a8SJakub Kicinskifrom lib.py import ksft_run, ksft_exit 5185646a8SJakub Kicinskifrom lib.py import ksft_ge, ksft_eq 6185646a8SJakub Kicinskifrom lib.py import KsftSkipEx 7185646a8SJakub Kicinskifrom lib.py import ksft_disruptive 8185646a8SJakub Kicinskifrom lib.py import EthtoolFamily, NetdevFamily 9185646a8SJakub Kicinskifrom lib.py import NetDrvEnv 10185646a8SJakub Kicinskifrom lib.py import cmd, ip, defer 11185646a8SJakub Kicinski 12185646a8SJakub Kicinski 13185646a8SJakub Kicinskidef read_affinity(irq) -> str: 14185646a8SJakub Kicinski with open(f'/proc/irq/{irq}/smp_affinity', 'r') as fp: 15185646a8SJakub Kicinski return fp.read().lstrip("0,").strip() 16185646a8SJakub Kicinski 17185646a8SJakub Kicinski 18185646a8SJakub Kicinskidef write_affinity(irq, what) -> str: 19185646a8SJakub Kicinski if what != read_affinity(irq): 20185646a8SJakub Kicinski with open(f'/proc/irq/{irq}/smp_affinity', 'w') as fp: 21185646a8SJakub Kicinski fp.write(what) 22185646a8SJakub Kicinski 23185646a8SJakub Kicinski 24185646a8SJakub Kicinskidef check_irqs_reported(cfg) -> None: 25185646a8SJakub Kicinski """ Check that device reports IRQs for NAPI instances """ 26185646a8SJakub Kicinski napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True) 27185646a8SJakub Kicinski irqs = sum(['irq' in x for x in napis]) 28185646a8SJakub Kicinski 29185646a8SJakub Kicinski ksft_ge(irqs, 1) 30185646a8SJakub Kicinski ksft_eq(irqs, len(napis)) 31185646a8SJakub Kicinski 32185646a8SJakub Kicinski 33185646a8SJakub Kicinskidef _check_reconfig(cfg, reconfig_cb) -> None: 34185646a8SJakub Kicinski napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True) 35185646a8SJakub Kicinski for n in reversed(napis): 36185646a8SJakub Kicinski if 'irq' in n: 37185646a8SJakub Kicinski break 38185646a8SJakub Kicinski else: 39185646a8SJakub Kicinski raise KsftSkipEx(f"Device has no NAPI with IRQ attribute (#napis: {len(napis)}") 40185646a8SJakub Kicinski 41185646a8SJakub Kicinski old = read_affinity(n['irq']) 42185646a8SJakub Kicinski # pick an affinity that's not the current one 43185646a8SJakub Kicinski new = "3" if old != "3" else "5" 44185646a8SJakub Kicinski write_affinity(n['irq'], new) 45185646a8SJakub Kicinski defer(write_affinity, n['irq'], old) 46185646a8SJakub Kicinski 47185646a8SJakub Kicinski reconfig_cb(cfg) 48185646a8SJakub Kicinski 49185646a8SJakub Kicinski ksft_eq(read_affinity(n['irq']), new, comment="IRQ affinity changed after reconfig") 50185646a8SJakub Kicinski 51185646a8SJakub Kicinski 52185646a8SJakub Kicinskidef check_reconfig_queues(cfg) -> None: 53185646a8SJakub Kicinski def reconfig(cfg) -> None: 54185646a8SJakub Kicinski channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}}) 55185646a8SJakub Kicinski if channels['combined-count'] == 0: 56185646a8SJakub Kicinski rx_type = 'rx' 57185646a8SJakub Kicinski else: 58185646a8SJakub Kicinski rx_type = 'combined' 59185646a8SJakub Kicinski cur_queue_cnt = channels[f'{rx_type}-count'] 60185646a8SJakub Kicinski max_queue_cnt = channels[f'{rx_type}-max'] 61185646a8SJakub Kicinski 62185646a8SJakub Kicinski cmd(f"ethtool -L {cfg.ifname} {rx_type} 1") 63185646a8SJakub Kicinski cmd(f"ethtool -L {cfg.ifname} {rx_type} {max_queue_cnt}") 64185646a8SJakub Kicinski cmd(f"ethtool -L {cfg.ifname} {rx_type} {cur_queue_cnt}") 65185646a8SJakub Kicinski 66185646a8SJakub Kicinski _check_reconfig(cfg, reconfig) 67185646a8SJakub Kicinski 68185646a8SJakub Kicinski 69185646a8SJakub Kicinskidef check_reconfig_xdp(cfg) -> None: 70185646a8SJakub Kicinski def reconfig(cfg) -> None: 71185646a8SJakub Kicinski ip(f"link set dev %s xdp obj %s sec xdp" % 72*c231e12eSJakub Kicinski (cfg.ifname, cfg.net_lib_dir / "xdp_dummy.bpf.o")) 73185646a8SJakub Kicinski ip(f"link set dev %s xdp off" % cfg.ifname) 74185646a8SJakub Kicinski 75185646a8SJakub Kicinski _check_reconfig(cfg, reconfig) 76185646a8SJakub Kicinski 77185646a8SJakub Kicinski 78185646a8SJakub Kicinski@ksft_disruptive 79185646a8SJakub Kicinskidef check_down(cfg) -> None: 80185646a8SJakub Kicinski def reconfig(cfg) -> None: 81185646a8SJakub Kicinski ip("link set dev %s down" % cfg.ifname) 82185646a8SJakub Kicinski ip("link set dev %s up" % cfg.ifname) 83185646a8SJakub Kicinski 84185646a8SJakub Kicinski _check_reconfig(cfg, reconfig) 85185646a8SJakub Kicinski 86185646a8SJakub Kicinski 87185646a8SJakub Kicinskidef main() -> None: 88185646a8SJakub Kicinski with NetDrvEnv(__file__, nsim_test=False) as cfg: 89185646a8SJakub Kicinski cfg.ethnl = EthtoolFamily() 90185646a8SJakub Kicinski cfg.netnl = NetdevFamily() 91185646a8SJakub Kicinski 92185646a8SJakub Kicinski ksft_run([check_irqs_reported, check_reconfig_queues, 93185646a8SJakub Kicinski check_reconfig_xdp, check_down], 94185646a8SJakub Kicinski args=(cfg, )) 95185646a8SJakub Kicinski ksft_exit() 96185646a8SJakub Kicinski 97185646a8SJakub Kicinski 98185646a8SJakub Kicinskiif __name__ == "__main__": 99185646a8SJakub Kicinski main() 100