xref: /linux/tools/testing/selftests/drivers/net/ring_reconfig.py (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1*ecca75aeSJakub Kicinski#!/usr/bin/env python3
2*ecca75aeSJakub Kicinski# SPDX-License-Identifier: GPL-2.0
3*ecca75aeSJakub Kicinski
4*ecca75aeSJakub Kicinski"""
5*ecca75aeSJakub KicinskiTest channel and ring size configuration via ethtool (-L / -G).
6*ecca75aeSJakub Kicinski"""
7*ecca75aeSJakub Kicinski
8*ecca75aeSJakub Kicinskifrom lib.py import ksft_run, ksft_exit, ksft_pr
9*ecca75aeSJakub Kicinskifrom lib.py import ksft_eq
10*ecca75aeSJakub Kicinskifrom lib.py import NetDrvEpEnv, EthtoolFamily, GenerateTraffic
11*ecca75aeSJakub Kicinskifrom lib.py import defer, NlError
12*ecca75aeSJakub Kicinski
13*ecca75aeSJakub Kicinski
14*ecca75aeSJakub Kicinskidef channels(cfg) -> None:
15*ecca75aeSJakub Kicinski    """
16*ecca75aeSJakub Kicinski    Twiddle channel counts in various combinations of parameters.
17*ecca75aeSJakub Kicinski    We're only looking for driver adhering to the requested config
18*ecca75aeSJakub Kicinski    if the config is accepted and crashes.
19*ecca75aeSJakub Kicinski    """
20*ecca75aeSJakub Kicinski    ehdr = {'header':{'dev-index': cfg.ifindex}}
21*ecca75aeSJakub Kicinski    chans = cfg.eth.channels_get(ehdr)
22*ecca75aeSJakub Kicinski
23*ecca75aeSJakub Kicinski    all_keys = ["rx", "tx", "combined"]
24*ecca75aeSJakub Kicinski    mixes = [{"combined"}, {"rx", "tx"}, {"rx", "combined"}, {"tx", "combined"},
25*ecca75aeSJakub Kicinski             {"rx", "tx", "combined"},]
26*ecca75aeSJakub Kicinski
27*ecca75aeSJakub Kicinski    # Get the set of keys that device actually supports
28*ecca75aeSJakub Kicinski    restore = {}
29*ecca75aeSJakub Kicinski    supported = set()
30*ecca75aeSJakub Kicinski    for key in all_keys:
31*ecca75aeSJakub Kicinski        if key + "-max" in chans:
32*ecca75aeSJakub Kicinski            supported.add(key)
33*ecca75aeSJakub Kicinski            restore |= {key + "-count": chans[key + "-count"]}
34*ecca75aeSJakub Kicinski
35*ecca75aeSJakub Kicinski    defer(cfg.eth.channels_set, ehdr | restore)
36*ecca75aeSJakub Kicinski
37*ecca75aeSJakub Kicinski    def test_config(config):
38*ecca75aeSJakub Kicinski        try:
39*ecca75aeSJakub Kicinski            cfg.eth.channels_set(ehdr | config)
40*ecca75aeSJakub Kicinski            get = cfg.eth.channels_get(ehdr)
41*ecca75aeSJakub Kicinski            for k, v in config.items():
42*ecca75aeSJakub Kicinski                ksft_eq(get.get(k, 0), v)
43*ecca75aeSJakub Kicinski        except NlError as e:
44*ecca75aeSJakub Kicinski            failed.append(mix)
45*ecca75aeSJakub Kicinski            ksft_pr("Can't set", config, e)
46*ecca75aeSJakub Kicinski        else:
47*ecca75aeSJakub Kicinski            ksft_pr("Okay", config)
48*ecca75aeSJakub Kicinski
49*ecca75aeSJakub Kicinski    failed = []
50*ecca75aeSJakub Kicinski    for mix in mixes:
51*ecca75aeSJakub Kicinski        if not mix.issubset(supported):
52*ecca75aeSJakub Kicinski            continue
53*ecca75aeSJakub Kicinski
54*ecca75aeSJakub Kicinski        # Set all the values in the mix to 1, other supported to 0
55*ecca75aeSJakub Kicinski        config = {}
56*ecca75aeSJakub Kicinski        for key in all_keys:
57*ecca75aeSJakub Kicinski            config[key + "-count"] = 1 if key in mix else 0
58*ecca75aeSJakub Kicinski        test_config(config)
59*ecca75aeSJakub Kicinski
60*ecca75aeSJakub Kicinski    for mix in mixes:
61*ecca75aeSJakub Kicinski        if not mix.issubset(supported):
62*ecca75aeSJakub Kicinski            continue
63*ecca75aeSJakub Kicinski        if mix in failed:
64*ecca75aeSJakub Kicinski            continue
65*ecca75aeSJakub Kicinski
66*ecca75aeSJakub Kicinski        # Set all the values in the mix to max, other supported to 0
67*ecca75aeSJakub Kicinski        config = {}
68*ecca75aeSJakub Kicinski        for key in all_keys:
69*ecca75aeSJakub Kicinski            config[key + "-count"] = chans[key + '-max'] if key in mix else 0
70*ecca75aeSJakub Kicinski        test_config(config)
71*ecca75aeSJakub Kicinski
72*ecca75aeSJakub Kicinski
73*ecca75aeSJakub Kicinskidef _configure_min_ring_cnt(cfg) -> None:
74*ecca75aeSJakub Kicinski    """ Try to configure a single Rx/Tx ring. """
75*ecca75aeSJakub Kicinski    ehdr = {'header':{'dev-index': cfg.ifindex}}
76*ecca75aeSJakub Kicinski    chans = cfg.eth.channels_get(ehdr)
77*ecca75aeSJakub Kicinski
78*ecca75aeSJakub Kicinski    all_keys = ["rx-count", "tx-count", "combined-count"]
79*ecca75aeSJakub Kicinski    restore = {}
80*ecca75aeSJakub Kicinski    config = {}
81*ecca75aeSJakub Kicinski    for key in all_keys:
82*ecca75aeSJakub Kicinski        if key in chans:
83*ecca75aeSJakub Kicinski            restore[key] = chans[key]
84*ecca75aeSJakub Kicinski            config[key] = 0
85*ecca75aeSJakub Kicinski
86*ecca75aeSJakub Kicinski    if chans.get('combined-count', 0) > 1:
87*ecca75aeSJakub Kicinski        config['combined-count'] = 1
88*ecca75aeSJakub Kicinski    elif chans.get('rx-count', 0) > 1 and chans.get('tx-count', 0) > 1:
89*ecca75aeSJakub Kicinski        config['tx-count'] = 1
90*ecca75aeSJakub Kicinski        config['rx-count'] = 1
91*ecca75aeSJakub Kicinski    else:
92*ecca75aeSJakub Kicinski        # looks like we're already on 1 channel
93*ecca75aeSJakub Kicinski        return
94*ecca75aeSJakub Kicinski
95*ecca75aeSJakub Kicinski    cfg.eth.channels_set(ehdr | config)
96*ecca75aeSJakub Kicinski    defer(cfg.eth.channels_set, ehdr | restore)
97*ecca75aeSJakub Kicinski
98*ecca75aeSJakub Kicinski
99*ecca75aeSJakub Kicinskidef ringparam(cfg) -> None:
100*ecca75aeSJakub Kicinski    """
101*ecca75aeSJakub Kicinski    Tweak the ringparam configuration. Try to run some traffic over min
102*ecca75aeSJakub Kicinski    ring size to make sure it actually functions.
103*ecca75aeSJakub Kicinski    """
104*ecca75aeSJakub Kicinski    ehdr = {'header':{'dev-index': cfg.ifindex}}
105*ecca75aeSJakub Kicinski    rings = cfg.eth.rings_get(ehdr)
106*ecca75aeSJakub Kicinski
107*ecca75aeSJakub Kicinski    restore = {}
108*ecca75aeSJakub Kicinski    maxes = {}
109*ecca75aeSJakub Kicinski    params = set()
110*ecca75aeSJakub Kicinski    for key in rings.keys():
111*ecca75aeSJakub Kicinski        if 'max' in key:
112*ecca75aeSJakub Kicinski            param = key[:-4]
113*ecca75aeSJakub Kicinski            maxes[param] = rings[key]
114*ecca75aeSJakub Kicinski            params.add(param)
115*ecca75aeSJakub Kicinski            restore[param] = rings[param]
116*ecca75aeSJakub Kicinski
117*ecca75aeSJakub Kicinski    defer(cfg.eth.rings_set, ehdr | restore)
118*ecca75aeSJakub Kicinski
119*ecca75aeSJakub Kicinski    # Speed up the reconfig by configuring just one ring
120*ecca75aeSJakub Kicinski    _configure_min_ring_cnt(cfg)
121*ecca75aeSJakub Kicinski
122*ecca75aeSJakub Kicinski    # Try to reach min on all settings
123*ecca75aeSJakub Kicinski    for param in params:
124*ecca75aeSJakub Kicinski        val = rings[param]
125*ecca75aeSJakub Kicinski        while True:
126*ecca75aeSJakub Kicinski            try:
127*ecca75aeSJakub Kicinski                cfg.eth.rings_set({'header':{'dev-index': cfg.ifindex},
128*ecca75aeSJakub Kicinski                                   param: val // 2})
129*ecca75aeSJakub Kicinski                if val == 0:
130*ecca75aeSJakub Kicinski                    break
131*ecca75aeSJakub Kicinski                val //= 2
132*ecca75aeSJakub Kicinski            except NlError:
133*ecca75aeSJakub Kicinski                break
134*ecca75aeSJakub Kicinski
135*ecca75aeSJakub Kicinski        get = cfg.eth.rings_get(ehdr)
136*ecca75aeSJakub Kicinski        ksft_eq(get[param], val)
137*ecca75aeSJakub Kicinski
138*ecca75aeSJakub Kicinski        ksft_pr(f"Reached min for '{param}' at {val} (max {rings[param]})")
139*ecca75aeSJakub Kicinski
140*ecca75aeSJakub Kicinski    GenerateTraffic(cfg).wait_pkts_and_stop(10000)
141*ecca75aeSJakub Kicinski
142*ecca75aeSJakub Kicinski    # Try max across all params, if the driver supports large rings
143*ecca75aeSJakub Kicinski    # this may OOM so we ignore errors
144*ecca75aeSJakub Kicinski    try:
145*ecca75aeSJakub Kicinski        ksft_pr("Applying max settings")
146*ecca75aeSJakub Kicinski        config = {p: maxes[p] for p in params}
147*ecca75aeSJakub Kicinski        cfg.eth.rings_set(ehdr | config)
148*ecca75aeSJakub Kicinski    except NlError as e:
149*ecca75aeSJakub Kicinski        ksft_pr("Can't set max params", config, e)
150*ecca75aeSJakub Kicinski    else:
151*ecca75aeSJakub Kicinski        GenerateTraffic(cfg).wait_pkts_and_stop(10000)
152*ecca75aeSJakub Kicinski
153*ecca75aeSJakub Kicinski
154*ecca75aeSJakub Kicinskidef main() -> None:
155*ecca75aeSJakub Kicinski    """ Ksft boiler plate main """
156*ecca75aeSJakub Kicinski
157*ecca75aeSJakub Kicinski    with NetDrvEpEnv(__file__) as cfg:
158*ecca75aeSJakub Kicinski        cfg.eth = EthtoolFamily()
159*ecca75aeSJakub Kicinski
160*ecca75aeSJakub Kicinski        ksft_run([channels,
161*ecca75aeSJakub Kicinski                  ringparam],
162*ecca75aeSJakub Kicinski                 args=(cfg, ))
163*ecca75aeSJakub Kicinski    ksft_exit()
164*ecca75aeSJakub Kicinski
165*ecca75aeSJakub Kicinski
166*ecca75aeSJakub Kicinskiif __name__ == "__main__":
167*ecca75aeSJakub Kicinski    main()
168