net/ena: fix build with GCC 12
[dpdk.git] / drivers / dma / idxd / dpdk_idxd_cfg.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2020 Intel Corporation
4
5 """
6 Configure an entire Intel DSA instance, using idxd kernel driver, for DPDK use
7 """
8
9 import sys
10 import argparse
11 import os
12 import os.path
13
14
15 class SysfsDir:
16     "Used to read/write paths in a sysfs directory"
17     def __init__(self, path):
18         self.path = path
19
20     def read_int(self, filename):
21         "Return a value from sysfs file"
22         with open(os.path.join(self.path, filename)) as f:
23             return int(f.readline())
24
25     def write_values(self, values):
26         "write dictionary, where key is filename and value is value to write"
27         for filename, contents in values.items():
28             with open(os.path.join(self.path, filename), "w") as f:
29                 f.write(str(contents))
30
31
32 def get_drv_dir(dtype):
33     "Get the sysfs path for the driver, either 'idxd' or 'user'"
34     drv_dir = "/sys/bus/dsa/drivers/" + dtype
35     if not os.path.exists(drv_dir):
36         return "/sys/bus/dsa/drivers/dsa"
37     return drv_dir
38
39
40 def reset_device(dsa_id):
41     "Reset the DSA device and all its queues"
42     drv_dir = SysfsDir(get_drv_dir("idxd"))
43     drv_dir.write_values({"unbind": f"dsa{dsa_id}"})
44
45
46 def get_pci_dir(pci):
47     "Search for the sysfs directory of the PCI device"
48     base_dir = '/sys/bus/pci/devices/'
49     for path, dirs, files in os.walk(base_dir):
50         for dir in dirs:
51             if pci in dir:
52                 return os.path.join(base_dir, dir)
53     sys.exit(f"Could not find sysfs directory for device {pci}")
54
55
56 def get_dsa_id(pci):
57     "Get the DSA instance ID using the PCI address of the device"
58     pci_dir = get_pci_dir(pci)
59     for path, dirs, files in os.walk(pci_dir):
60         for dir in dirs:
61             if dir.startswith('dsa') and 'wq' not in dir:
62                 return int(dir[3:])
63     sys.exit(f"Could not get device ID for device {pci}")
64
65
66 def parse_wq_opts(wq_opts):
67     "Parse user-specified queue configuration, creating a dict of options"
68     try:
69         return {o.split('=')[0]: o.split('=')[1] for o in wq_opts}
70     except ValueError:
71         sys.exit("Invalid --wq-option format, use format 'option=value'")
72
73
74 def configure_dsa(dsa_id, args):
75     "Configure the DSA instance with appropriate number of queues"
76     dsa_dir = SysfsDir(f"/sys/bus/dsa/devices/dsa{dsa_id}")
77
78     max_groups = dsa_dir.read_int("max_groups")
79     max_engines = dsa_dir.read_int("max_engines")
80     max_queues = dsa_dir.read_int("max_work_queues")
81     max_work_queues_size = dsa_dir.read_int("max_work_queues_size")
82
83     nb_queues = min(args.q, max_queues)
84     if args.q > nb_queues:
85         print(f"Setting number of queues to max supported value: {max_queues}")
86
87     # we want one engine per group, and no more engines than queues
88     nb_groups = min(max_engines, max_groups, nb_queues)
89     for grp in range(nb_groups):
90         dsa_dir.write_values({f"engine{dsa_id}.{grp}/group_id": grp})
91
92     # configure each queue
93     for q in range(nb_queues):
94         wqcfg = {"group_id": q % nb_groups,
95                  "type": "user",
96                  "mode": "dedicated",
97                  "name": f"{args.prefix}_wq{dsa_id}.{q}",
98                  "priority": 1,
99                  "max_batch_size": 1024,
100                  "size": int(max_work_queues_size / nb_queues)}
101         wqcfg.update(parse_wq_opts(args.wq_option))
102         wq_dir = SysfsDir(os.path.join(dsa_dir.path, f"wq{dsa_id}.{q}"))
103         wq_dir.write_values(wqcfg)
104
105     # enable device and then queues
106     idxd_dir = SysfsDir(get_drv_dir("idxd"))
107     idxd_dir.write_values({"bind": f"dsa{dsa_id}"})
108
109     user_dir = SysfsDir(get_drv_dir("user"))
110     for q in range(nb_queues):
111         user_dir.write_values({"bind": f"wq{dsa_id}.{q}"})
112
113
114 def main(args):
115     "Main function, does arg parsing and calls config function"
116     arg_p = argparse.ArgumentParser(
117         description="Configure whole DSA device instance for DPDK use")
118     arg_p.add_argument('dsa_id',
119                        help="Specify DSA instance either via DSA instance number or PCI address")
120     arg_p.add_argument('-q', metavar='queues', type=int, default=255,
121                        help="Number of queues to set up")
122     arg_p.add_argument('--name-prefix', metavar='prefix', dest='prefix',
123                        default="dpdk",
124                        help="Prefix for workqueue name to mark for DPDK use [default: 'dpdk']")
125     arg_p.add_argument('--wq-option', action='append',
126                        help="Provide additional config option for queues (format 'x=y')")
127     arg_p.add_argument('--reset', action='store_true',
128                        help="Reset DSA device and its queues")
129     parsed_args = arg_p.parse_args(args[1:])
130
131     dsa_id = parsed_args.dsa_id
132     dsa_id = get_dsa_id(dsa_id) if ':' in dsa_id else dsa_id
133     if parsed_args.reset:
134         reset_device(dsa_id)
135     else:
136         configure_dsa(dsa_id, parsed_args)
137
138
139 if __name__ == "__main__":
140     main(sys.argv)