xref: /dpdk/usertools/dpdk-devbind.py (revision a7d69cef8f20a9aeab4657c20ca3e424823163cd)
13f6f8362SLouise Kilheeney#!/usr/bin/env python3
29d7c01f8SBruce Richardson# SPDX-License-Identifier: BSD-3-Clause
39d7c01f8SBruce Richardson# Copyright(c) 2010-2014 Intel Corporation
4c6dab2a8SThomas Monjalon#
5c6dab2a8SThomas Monjalon
6c6dab2a8SThomas Monjalonimport sys
7c6dab2a8SThomas Monjalonimport os
8c6dab2a8SThomas Monjalonimport subprocess
981255f27SStephen Hemmingerimport argparse
107a016af4SYongxin Liuimport platform
1181255f27SStephen Hemminger
12781eafc9SBruce Richardsonfrom glob import glob
131bb98a90SStephen Hemmingerfrom os.path import exists, basename
14781eafc9SBruce Richardsonfrom os.path import join as path_join
15c6dab2a8SThomas Monjalon
168ad08a28SGuduri Prathyusha# The PCI base class for all devices
178ad08a28SGuduri Prathyushanetwork_class = {'Class': '02', 'Vendor': None, 'Device': None,
188ad08a28SGuduri Prathyusha                 'SVendor': None, 'SDevice': None}
1907488e29SNicolas Chautruacceleration_class = {'Class': '12', 'Vendor': None, 'Device': None,
2007488e29SNicolas Chautru                      'SVendor': None, 'SDevice': None}
21c01c748eSRosen Xuifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30',
22c01c748eSRosen Xu               'SVendor': None, 'SDevice': None}
238ad08a28SGuduri Prathyushaencryption_class = {'Class': '10', 'Vendor': None, 'Device': None,
248ad08a28SGuduri Prathyusha                    'SVendor': None, 'SDevice': None}
258ad08a28SGuduri Prathyushaintel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,
268ad08a28SGuduri Prathyusha                         'SVendor': None, 'SDevice': None}
2732a02dbfSGuduri Prathyushacavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d',
2832a02dbfSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
2980a1858dSGuduri Prathyushacavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053',
3080a1858dSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
31156c42eaSJerin Jacobcavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049',
32156c42eaSJerin Jacob              'SVendor': None, 'SDevice': None}
33f4bc0010SPavan Nikhileshcavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051',
34f4bc0010SPavan Nikhilesh              'SVendor': None, 'SDevice': None}
359d35895eSSunila Sahucavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037',
369d35895eSSunila Sahu              'SVendor': None, 'SDevice': None}
3720526313SXiaohua Zhangavp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110',
3820526313SXiaohua Zhang            'SVendor': None, 'SDevice': None}
398ad08a28SGuduri Prathyusha
4024d9c5d5STomasz Duszynskicnxk_bphy = {'Class': '08', 'Vendor': '177d', 'Device': 'a089',
4124d9c5d5STomasz Duszynski             'SVendor': None, 'SDevice': None}
423d27e49eSTomasz Duszynskicnxk_bphy_cgx = {'Class': '08', 'Vendor': '177d', 'Device': 'a059,a060',
433d27e49eSTomasz Duszynski                 'SVendor': None, 'SDevice': None}
442ff80151SRadha Mohan Chintakuntlacnxk_dma = {'Class': '08', 'Vendor': '177d', 'Device': 'a081',
452ff80151SRadha Mohan Chintakuntla            'SVendor': None, 'SDevice': None}
4669daa9e5SNithin Dabilpuramcnxk_inl_dev = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f0,a0f1',
4769daa9e5SNithin Dabilpuram                'SVendor': None, 'SDevice': None}
480bcc6644SJerin Jacob
49fb73eb2fSChengwen Fenghisilicon_dma = {'Class': '08', 'Vendor': '19e5', 'Device': 'a122',
50fb73eb2fSChengwen Feng                 'SVendor': None, 'SDevice': None}
511bbc35a8SAnoob Josephodm_dma = {'Class': '08', 'Vendor': '177d', 'Device': 'a08c',
521bbc35a8SAnoob Joseph           'SVendor': None, 'SDevice': None}
53fb73eb2fSChengwen Feng
54240078c0STimothy McDanielintel_dlb = {'Class': '0b', 'Vendor': '8086', 'Device': '270b,2710,2714',
55240078c0STimothy McDaniel             'SVendor': None, 'SDevice': None}
56c358ba7aSStephen Hemmingerintel_ioat_bdw = {'Class': '08', 'Vendor': '8086',
57c358ba7aSStephen Hemminger                  'Device': '6f20,6f21,6f22,6f23,6f24,6f25,6f26,6f27,6f2e,6f2f',
5812d4777aSBruce Richardson                  'SVendor': None, 'SDevice': None}
5912d4777aSBruce Richardsonintel_ioat_skx = {'Class': '08', 'Vendor': '8086', 'Device': '2021',
6012d4777aSBruce Richardson                  'SVendor': None, 'SDevice': None}
61299e282fSRadu Nicolauintel_ioat_icx = {'Class': '08', 'Vendor': '8086', 'Device': '0b00',
62299e282fSRadu Nicolau                  'SVendor': None, 'SDevice': None}
6343f9b521SKevin Laatzintel_idxd_spr = {'Class': '08', 'Vendor': '8086', 'Device': '0b25',
6443f9b521SKevin Laatz                  'SVendor': None, 'SDevice': None}
65034c328eSXiaoyun Liintel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
66034c328eSXiaoyun Li                 'SVendor': None, 'SDevice': None}
67f5057be3SXiaoyun Liintel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
68f5057be3SXiaoyun Li                 'SVendor': None, 'SDevice': None}
6912d4777aSBruce Richardson
7033e71acfSJerin Jacobcnxk_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f9,a0fa',
712ff80151SRadha Mohan Chintakuntla            'SVendor': None, 'SDevice': None}
7233e71acfSJerin Jacobcnxk_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc',
732ff80151SRadha Mohan Chintakuntla            'SVendor': None, 'SDevice': None}
7433e71acfSJerin Jacobcn9k_ree = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f4',
752ff80151SRadha Mohan Chintakuntla            'SVendor': None, 'SDevice': None}
762ff80151SRadha Mohan Chintakuntla
771216ac76SAndy Peivirtio_blk = {'Class': '01', 'Vendor': "1af4", 'Device': '1001,1042',
781216ac76SAndy Pei              'SVendor': None, 'SDevice': None}
791216ac76SAndy Pei
80b9aaa675SSrikanth Yalavarthicnxk_ml = {'Class': '08', 'Vendor': '177d', 'Device': 'a092',
81b9aaa675SSrikanth Yalavarthi           'SVendor': None, 'SDevice': None}
82b9aaa675SSrikanth Yalavarthi
83c01c748eSRosen Xunetwork_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
8407488e29SNicolas Chautrubaseband_devices = [acceleration_class]
858ad08a28SGuduri Prathyushacrypto_devices = [encryption_class, intel_processor_class]
862ff80151SRadha Mohan Chintakuntladma_devices = [cnxk_dma, hisilicon_dma,
871bbc35a8SAnoob Joseph               intel_idxd_spr, intel_ioat_bdw, intel_ioat_icx, intel_ioat_skx,
881bbc35a8SAnoob Joseph               odm_dma]
8933e71acfSJerin Jacobeventdev_devices = [cavium_sso, cavium_tim, intel_dlb, cnxk_sso]
9033e71acfSJerin Jacobmempool_devices = [cavium_fpa, cnxk_npa]
919d35895eSSunila Sahucompress_devices = [cavium_zip]
9233e71acfSJerin Jacobregex_devices = [cn9k_ree]
93b9aaa675SSrikanth Yalavarthiml_devices = [cnxk_ml]
942ff80151SRadha Mohan Chintakuntlamisc_devices = [cnxk_bphy, cnxk_bphy_cgx, cnxk_inl_dev,
951216ac76SAndy Pei                intel_ntb_skx, intel_ntb_icx,
961216ac76SAndy Pei                virtio_blk]
97c6dab2a8SThomas Monjalon
98c6dab2a8SThomas Monjalon# global dict ethernet devices present. Dictionary indexed by PCI address.
99c6dab2a8SThomas Monjalon# Each device within this is itself a dictionary of device properties
100c6dab2a8SThomas Monjalondevices = {}
101c6dab2a8SThomas Monjalon# list of supported DPDK drivers
102c6dab2a8SThomas Monjalondpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"]
103681a6728SAnatoly Burakov# list of currently loaded kernel modules
104681a6728SAnatoly Burakovloaded_modules = None
105c6dab2a8SThomas Monjalon
106c6dab2a8SThomas Monjalon# command-line arg flags
107c6dab2a8SThomas Monjalonb_flag = None
108c6dab2a8SThomas Monjalonstatus_flag = False
109c6dab2a8SThomas Monjalonforce_flag = False
1106ca0f1c8SFidaullah Noonarinoiommu_flag = False
111c6dab2a8SThomas Monjalonargs = []
112c6dab2a8SThomas Monjalon
11362d3ce60SStephen Hemminger
114*a7d69cefSAnatoly Burakov# check if this system has NUMA support
115*a7d69cefSAnatoly Burakovdef is_numa():
116*a7d69cefSAnatoly Burakov    return os.path.exists('/sys/devices/system/node')
117*a7d69cefSAnatoly Burakov
118*a7d69cefSAnatoly Burakov
119681a6728SAnatoly Burakov# check if a specific kernel module is loaded
120681a6728SAnatoly Burakovdef module_is_loaded(module):
121681a6728SAnatoly Burakov    global loaded_modules
122681a6728SAnatoly Burakov
12343623124SPavan Nikhilesh    if module == 'vfio_pci':
12443623124SPavan Nikhilesh        module = 'vfio-pci'
12543623124SPavan Nikhilesh
126681a6728SAnatoly Burakov    if loaded_modules:
127681a6728SAnatoly Burakov        return module in loaded_modules
128681a6728SAnatoly Burakov
129681a6728SAnatoly Burakov    # Get list of sysfs modules (both built-in and dynamically loaded)
130681a6728SAnatoly Burakov    sysfs_path = '/sys/module/'
131681a6728SAnatoly Burakov
132681a6728SAnatoly Burakov    # Get the list of directories in sysfs_path
133681a6728SAnatoly Burakov    sysfs_mods = [m for m in os.listdir(sysfs_path)
134681a6728SAnatoly Burakov                  if os.path.isdir(os.path.join(sysfs_path, m))]
135681a6728SAnatoly Burakov
136681a6728SAnatoly Burakov    # special case for vfio_pci (module is named vfio-pci,
137681a6728SAnatoly Burakov    # but its .ko is named vfio_pci)
138681a6728SAnatoly Burakov    sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods]
139681a6728SAnatoly Burakov
140681a6728SAnatoly Burakov    loaded_modules = sysfs_mods
141681a6728SAnatoly Burakov
1427a016af4SYongxin Liu    # add built-in modules as loaded
1437a016af4SYongxin Liu    release = platform.uname().release
1447a016af4SYongxin Liu    filename = os.path.join("/lib/modules/", release, "modules.builtin")
1457a016af4SYongxin Liu    if os.path.exists(filename):
1467a016af4SYongxin Liu        try:
1477a016af4SYongxin Liu            with open(filename) as f:
1487a016af4SYongxin Liu                loaded_modules += [os.path.splitext(os.path.basename(mod))[0] for mod in f]
1497a016af4SYongxin Liu        except IOError:
1507a016af4SYongxin Liu            print("Warning: cannot read list of built-in kernel modules")
1517a016af4SYongxin Liu
1527a016af4SYongxin Liu    return module in loaded_modules
153681a6728SAnatoly Burakov
154c6dab2a8SThomas Monjalon
155c6dab2a8SThomas Monjalondef check_modules():
156c6dab2a8SThomas Monjalon    '''Checks that igb_uio is loaded'''
157c6dab2a8SThomas Monjalon    global dpdk_drivers
158c6dab2a8SThomas Monjalon
159c6dab2a8SThomas Monjalon    # list of supported modules
160c6dab2a8SThomas Monjalon    mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers]
161c6dab2a8SThomas Monjalon
162c6dab2a8SThomas Monjalon    # first check if module is loaded
163c6dab2a8SThomas Monjalon    for mod in mods:
164681a6728SAnatoly Burakov        if module_is_loaded(mod["Name"]):
165c6dab2a8SThomas Monjalon            mod["Found"] = True
166c6dab2a8SThomas Monjalon
167c6dab2a8SThomas Monjalon    # check if we have at least one loaded module
168c6dab2a8SThomas Monjalon    if True not in [mod["Found"] for mod in mods] and b_flag is not None:
1692804529fSAnatoly Burakov        print("Warning: no supported DPDK kernel modules are loaded", file=sys.stderr)
170c6dab2a8SThomas Monjalon
171c6dab2a8SThomas Monjalon    # change DPDK driver list to only contain drivers that are loaded
172c6dab2a8SThomas Monjalon    dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]]
173c6dab2a8SThomas Monjalon
174c6dab2a8SThomas Monjalon
175c6dab2a8SThomas Monjalondef has_driver(dev_id):
176c6dab2a8SThomas Monjalon    '''return true if a device is assigned to a driver. False otherwise'''
177c6dab2a8SThomas Monjalon    return "Driver_str" in devices[dev_id]
178c6dab2a8SThomas Monjalon
179c6dab2a8SThomas Monjalon
180c3ce205dSGuduri Prathyushadef get_pci_device_details(dev_id, probe_lspci):
181c6dab2a8SThomas Monjalon    '''This function gets additional details for a PCI device'''
182c6dab2a8SThomas Monjalon    device = {}
183c6dab2a8SThomas Monjalon
184c3ce205dSGuduri Prathyusha    if probe_lspci:
1853f6f8362SLouise Kilheeney        extra_info = subprocess.check_output(["lspci", "-vmmks", dev_id]).splitlines()
186c6dab2a8SThomas Monjalon        # parse lspci details
187c6dab2a8SThomas Monjalon        for line in extra_info:
188d58360c6SStephen Hemminger            if not line:
189c6dab2a8SThomas Monjalon                continue
19008ab6cd3SChristos Ricudis            name, value = line.decode("utf8").split("\t", 1)
191c6dab2a8SThomas Monjalon            name = name.strip(":") + "_str"
192c6dab2a8SThomas Monjalon            device[name] = value
193c6dab2a8SThomas Monjalon    # check for a unix interface name
194c6dab2a8SThomas Monjalon    device["Interface"] = ""
195c6dab2a8SThomas Monjalon    for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id):
196c6dab2a8SThomas Monjalon        if "net" in dirs:
197c6dab2a8SThomas Monjalon            device["Interface"] = \
198c6dab2a8SThomas Monjalon                ",".join(os.listdir(os.path.join(base, "net")))
199c6dab2a8SThomas Monjalon            break
200c6dab2a8SThomas Monjalon    # check if a port is used for ssh connection
201c6dab2a8SThomas Monjalon    device["Ssh_if"] = False
202c6dab2a8SThomas Monjalon    device["Active"] = ""
203c6dab2a8SThomas Monjalon
204c6dab2a8SThomas Monjalon    return device
205c6dab2a8SThomas Monjalon
20662d3ce60SStephen Hemminger
207ea9f00f7SGuduri Prathyushadef clear_data():
208ea9f00f7SGuduri Prathyusha    '''This function clears any old data'''
20993b93bebSTimothy Redaelli    global devices
210ea9f00f7SGuduri Prathyusha    devices = {}
211c6dab2a8SThomas Monjalon
21262d3ce60SStephen Hemminger
213ea9f00f7SGuduri Prathyushadef get_device_details(devices_type):
214c6dab2a8SThomas Monjalon    '''This function populates the "devices" dictionary. The keys used are
215c6dab2a8SThomas Monjalon    the pci addresses (domain:bus:slot.func). The values are themselves
216c6dab2a8SThomas Monjalon    dictionaries - one for each NIC.'''
217c6dab2a8SThomas Monjalon    global devices
218c6dab2a8SThomas Monjalon    global dpdk_drivers
219c6dab2a8SThomas Monjalon
220c6dab2a8SThomas Monjalon    # first loop through and read details for all devices
221c3ce205dSGuduri Prathyusha    # request machine readable format, with numeric IDs and String
222c6dab2a8SThomas Monjalon    dev = {}
2233f6f8362SLouise Kilheeney    dev_lines = subprocess.check_output(["lspci", "-Dvmmnnk"]).splitlines()
224c6dab2a8SThomas Monjalon    for dev_line in dev_lines:
225d58360c6SStephen Hemminger        if not dev_line:
2268ad08a28SGuduri Prathyusha            if device_type_match(dev, devices_type):
2278ad08a28SGuduri Prathyusha                # Replace "Driver" with "Driver_str" to have consistency of
2288ad08a28SGuduri Prathyusha                # of dictionary key names
229c3ce205dSGuduri Prathyusha                if "Driver" in dev.keys():
230c3ce205dSGuduri Prathyusha                    dev["Driver_str"] = dev.pop("Driver")
231c76a10ecSAnatoly Burakov                if "Module" in dev.keys():
232c76a10ecSAnatoly Burakov                    dev["Module_str"] = dev.pop("Module")
233c6dab2a8SThomas Monjalon                # use dict to make copy of dev
234c6dab2a8SThomas Monjalon                devices[dev["Slot"]] = dict(dev)
235c3ce205dSGuduri Prathyusha            # Clear previous device's data
236c3ce205dSGuduri Prathyusha            dev = {}
237c6dab2a8SThomas Monjalon        else:
23808ab6cd3SChristos Ricudis            name, value = dev_line.decode("utf8").split("\t", 1)
239c3ce205dSGuduri Prathyusha            value_list = value.rsplit(' ', 1)
240d58360c6SStephen Hemminger            if value_list:
241c3ce205dSGuduri Prathyusha                # String stored in <name>_str
242c3ce205dSGuduri Prathyusha                dev[name.rstrip(":") + '_str'] = value_list[0]
243c3ce205dSGuduri Prathyusha            # Numeric IDs
244c3ce205dSGuduri Prathyusha            dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
245c3ce205dSGuduri Prathyusha                .rstrip("]").lstrip("[")
246c6dab2a8SThomas Monjalon
2478ad08a28SGuduri Prathyusha    if devices_type == network_devices:
248c6dab2a8SThomas Monjalon        # check what is the interface if any for an ssh connection if
249c6dab2a8SThomas Monjalon        # any to this host, so we can mark it later.
250c6dab2a8SThomas Monjalon        ssh_if = []
2513f6f8362SLouise Kilheeney        route = subprocess.check_output(["ip", "-o", "route"])
252c6dab2a8SThomas Monjalon        # filter out all lines for 169.254 routes
253c6dab2a8SThomas Monjalon        route = "\n".join(filter(lambda ln: not ln.startswith("169.254"),
254c6dab2a8SThomas Monjalon                                 route.decode().splitlines()))
255c6dab2a8SThomas Monjalon        rt_info = route.split()
256c6dab2a8SThomas Monjalon        for i in range(len(rt_info) - 1):
257c6dab2a8SThomas Monjalon            if rt_info[i] == "dev":
258c6dab2a8SThomas Monjalon                ssh_if.append(rt_info[i + 1])
259c6dab2a8SThomas Monjalon
260c6dab2a8SThomas Monjalon    # based on the basic info, get extended text details
261c6dab2a8SThomas Monjalon    for d in devices.keys():
2628ad08a28SGuduri Prathyusha        if not device_type_match(devices[d], devices_type):
263617d9052SYoni Gilad            continue
264617d9052SYoni Gilad
265c6dab2a8SThomas Monjalon        # get additional info and add it to existing data
266c6dab2a8SThomas Monjalon        devices[d] = devices[d].copy()
267c3ce205dSGuduri Prathyusha        # No need to probe lspci
268c3ce205dSGuduri Prathyusha        devices[d].update(get_pci_device_details(d, False).items())
269c6dab2a8SThomas Monjalon
2708ad08a28SGuduri Prathyusha        if devices_type == network_devices:
271ea9f00f7SGuduri Prathyusha            for _if in ssh_if:
272ea9f00f7SGuduri Prathyusha                if _if in devices[d]["Interface"].split(","):
273ea9f00f7SGuduri Prathyusha                    devices[d]["Ssh_if"] = True
274ea9f00f7SGuduri Prathyusha                    devices[d]["Active"] = "*Active*"
275ea9f00f7SGuduri Prathyusha                    break
276ea9f00f7SGuduri Prathyusha
277c6dab2a8SThomas Monjalon        # add igb_uio to list of supporting modules if needed
278c6dab2a8SThomas Monjalon        if "Module_str" in devices[d]:
279c6dab2a8SThomas Monjalon            for driver in dpdk_drivers:
280c6dab2a8SThomas Monjalon                if driver not in devices[d]["Module_str"]:
281c6dab2a8SThomas Monjalon                    devices[d]["Module_str"] = \
282c6dab2a8SThomas Monjalon                        devices[d]["Module_str"] + ",%s" % driver
283c6dab2a8SThomas Monjalon        else:
284c6dab2a8SThomas Monjalon            devices[d]["Module_str"] = ",".join(dpdk_drivers)
285c6dab2a8SThomas Monjalon
286c6dab2a8SThomas Monjalon        # make sure the driver and module strings do not have any duplicates
287c6dab2a8SThomas Monjalon        if has_driver(d):
288c6dab2a8SThomas Monjalon            modules = devices[d]["Module_str"].split(",")
289c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in modules:
290c6dab2a8SThomas Monjalon                modules.remove(devices[d]["Driver_str"])
291c6dab2a8SThomas Monjalon                devices[d]["Module_str"] = ",".join(modules)
292c6dab2a8SThomas Monjalon
293c6dab2a8SThomas Monjalon
2948ad08a28SGuduri Prathyushadef device_type_match(dev, devices_type):
2958ad08a28SGuduri Prathyusha    for i in range(len(devices_type)):
2968ad08a28SGuduri Prathyusha        param_count = len(
2978ad08a28SGuduri Prathyusha            [x for x in devices_type[i].values() if x is not None])
2988ad08a28SGuduri Prathyusha        match_count = 0
2998ad08a28SGuduri Prathyusha        if dev["Class"][0:2] == devices_type[i]["Class"]:
3008ad08a28SGuduri Prathyusha            match_count = match_count + 1
3018ad08a28SGuduri Prathyusha            for key in devices_type[i].keys():
3028ad08a28SGuduri Prathyusha                if key != 'Class' and devices_type[i][key]:
3038ad08a28SGuduri Prathyusha                    value_list = devices_type[i][key].split(',')
3048ad08a28SGuduri Prathyusha                    for value in value_list:
3058ad08a28SGuduri Prathyusha                        if value.strip(' ') == dev[key]:
3068ad08a28SGuduri Prathyusha                            match_count = match_count + 1
3078ad08a28SGuduri Prathyusha            # count must be the number of non None parameters to match
3088ad08a28SGuduri Prathyusha            if match_count == param_count:
3098ad08a28SGuduri Prathyusha                return True
3108ad08a28SGuduri Prathyusha    return False
3118ad08a28SGuduri Prathyusha
31262d3ce60SStephen Hemminger
313c6dab2a8SThomas Monjalondef dev_id_from_dev_name(dev_name):
314c6dab2a8SThomas Monjalon    '''Take a device "name" - a string passed in by user to identify a NIC
315c6dab2a8SThomas Monjalon    device, and determine the device id - i.e. the domain:bus:slot.func - for
316c6dab2a8SThomas Monjalon    it, which can then be used to index into the devices array'''
317c6dab2a8SThomas Monjalon
318c6dab2a8SThomas Monjalon    # check if it's already a suitable index
319c6dab2a8SThomas Monjalon    if dev_name in devices:
320c6dab2a8SThomas Monjalon        return dev_name
321c6dab2a8SThomas Monjalon    # check if it's an index just missing the domain part
322b5685e39SStephen Hemminger    if "0000:" + dev_name in devices:
323c6dab2a8SThomas Monjalon        return "0000:" + dev_name
324b5685e39SStephen Hemminger
325c6dab2a8SThomas Monjalon    # check if it's an interface name, e.g. eth1
326c6dab2a8SThomas Monjalon    for d in devices.keys():
327c6dab2a8SThomas Monjalon        if dev_name in devices[d]["Interface"].split(","):
328c6dab2a8SThomas Monjalon            return devices[d]["Slot"]
329c6dab2a8SThomas Monjalon    # if nothing else matches - error
33015f6aac7SAnatoly Burakov    raise ValueError("Unknown device: %s. "
331c6dab2a8SThomas Monjalon                     "Please specify device in \"bus:slot.func\" format" % dev_name)
332c6dab2a8SThomas Monjalon
333c6dab2a8SThomas Monjalon
334c6dab2a8SThomas Monjalondef unbind_one(dev_id, force):
335c6dab2a8SThomas Monjalon    '''Unbind the device identified by "dev_id" from its current driver'''
336c6dab2a8SThomas Monjalon    dev = devices[dev_id]
337c6dab2a8SThomas Monjalon    if not has_driver(dev_id):
3382804529fSAnatoly Burakov        print("Notice: %s %s %s is not currently managed by any driver" %
3392804529fSAnatoly Burakov              (dev["Slot"], dev["Device_str"], dev["Interface"]), file=sys.stderr)
340c6dab2a8SThomas Monjalon        return
341c6dab2a8SThomas Monjalon
342c6dab2a8SThomas Monjalon    # prevent us disconnecting ourselves
343c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
3442804529fSAnatoly Burakov        print("Warning: routing table indicates that interface %s is active. "
3452804529fSAnatoly Burakov              "Skipping unbind" % dev_id, file=sys.stderr)
346c6dab2a8SThomas Monjalon        return
347c6dab2a8SThomas Monjalon
348c6dab2a8SThomas Monjalon    # write to /sys to unbind
349c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
350c6dab2a8SThomas Monjalon    try:
351c6dab2a8SThomas Monjalon        f = open(filename, "a")
35262d3ce60SStephen Hemminger    except OSError as err:
35362d3ce60SStephen Hemminger        sys.exit("Error: unbind failed for %s - Cannot open %s: %s" %
35462d3ce60SStephen Hemminger                 (dev_id, filename, err))
355c6dab2a8SThomas Monjalon    f.write(dev_id)
356c6dab2a8SThomas Monjalon    f.close()
357c6dab2a8SThomas Monjalon
358c6dab2a8SThomas Monjalon
359c6dab2a8SThomas Monjalondef bind_one(dev_id, driver, force):
360c6dab2a8SThomas Monjalon    '''Bind the device given by "dev_id" to the driver "driver". If the device
361c6dab2a8SThomas Monjalon    is already bound to a different driver, it will be unbound first'''
362c6dab2a8SThomas Monjalon    dev = devices[dev_id]
363c6dab2a8SThomas Monjalon    saved_driver = None  # used to rollback any unbind in case of failure
364c6dab2a8SThomas Monjalon
365c6dab2a8SThomas Monjalon    # prevent disconnection of our ssh session
366c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
3672804529fSAnatoly Burakov        print("Warning: routing table indicates that interface %s is active. "
3682804529fSAnatoly Burakov              "Not modifying" % dev_id, file=sys.stderr)
369c6dab2a8SThomas Monjalon        return
370c6dab2a8SThomas Monjalon
371c6dab2a8SThomas Monjalon    # unbind any existing drivers we don't want
372c6dab2a8SThomas Monjalon    if has_driver(dev_id):
373c6dab2a8SThomas Monjalon        if dev["Driver_str"] == driver:
3742804529fSAnatoly Burakov            print("Notice: %s already bound to driver %s, skipping" %
3752804529fSAnatoly Burakov                  (dev_id, driver), file=sys.stderr)
376c6dab2a8SThomas Monjalon            return
377c6dab2a8SThomas Monjalon        saved_driver = dev["Driver_str"]
378c6dab2a8SThomas Monjalon        unbind_one(dev_id, force)
379c6dab2a8SThomas Monjalon        dev["Driver_str"] = ""  # clear driver string
380c6dab2a8SThomas Monjalon
3812fc35029SGuduri Prathyusha    # For kernels >= 3.15 driver_override can be used to specify the driver
3822fc35029SGuduri Prathyusha    # for a device rather than relying on the driver to provide a positive
3832fc35029SGuduri Prathyusha    # match of the device.  The existing process of looking up
3842fc35029SGuduri Prathyusha    # the vendor and device ID, adding them to the driver new_id,
3852fc35029SGuduri Prathyusha    # will erroneously bind other devices too which has the additional burden
3862fc35029SGuduri Prathyusha    # of unbinding those devices
387c6dab2a8SThomas Monjalon    if driver in dpdk_drivers:
3882fc35029SGuduri Prathyusha        filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
3891bb98a90SStephen Hemminger        if exists(filename):
3902fc35029SGuduri Prathyusha            try:
3912fc35029SGuduri Prathyusha                f = open(filename, "w")
39262d3ce60SStephen Hemminger            except OSError as err:
39362d3ce60SStephen Hemminger                print("Error: bind failed for %s - Cannot open %s: %s"
39462d3ce60SStephen Hemminger                      % (dev_id, filename, err), file=sys.stderr)
3952fc35029SGuduri Prathyusha                return
3962fc35029SGuduri Prathyusha            try:
3972fc35029SGuduri Prathyusha                f.write("%s" % driver)
3982fc35029SGuduri Prathyusha                f.close()
39962d3ce60SStephen Hemminger            except OSError as err:
4002fc35029SGuduri Prathyusha                print("Error: bind failed for %s - Cannot write driver %s to "
40162d3ce60SStephen Hemminger                      "PCI ID: %s" % (dev_id, driver, err), file=sys.stderr)
4022fc35029SGuduri Prathyusha                return
4032fc35029SGuduri Prathyusha        # For kernels < 3.15 use new_id to add PCI id's to the driver
4042fc35029SGuduri Prathyusha        else:
405c6dab2a8SThomas Monjalon            filename = "/sys/bus/pci/drivers/%s/new_id" % driver
406c6dab2a8SThomas Monjalon            try:
407c6dab2a8SThomas Monjalon                f = open(filename, "w")
40862d3ce60SStephen Hemminger            except OSError as err:
40962d3ce60SStephen Hemminger                print("Error: bind failed for %s - Cannot open %s: %s"
41062d3ce60SStephen Hemminger                      % (dev_id, filename, err), file=sys.stderr)
411c6dab2a8SThomas Monjalon                return
412c6dab2a8SThomas Monjalon            try:
4138ad08a28SGuduri Prathyusha                # Convert Device and Vendor Id to int to write to new_id
4148ad08a28SGuduri Prathyusha                f.write("%04x %04x" % (int(dev["Vendor"], 16),
4158ad08a28SGuduri Prathyusha                                       int(dev["Device"], 16)))
416c6dab2a8SThomas Monjalon                f.close()
41762d3ce60SStephen Hemminger            except OSError as err:
418c6dab2a8SThomas Monjalon                print("Error: bind failed for %s - Cannot write new PCI ID to "
41962d3ce60SStephen Hemminger                      "driver %s: %s" % (dev_id, driver, err), file=sys.stderr)
420c6dab2a8SThomas Monjalon                return
421c6dab2a8SThomas Monjalon
422c6dab2a8SThomas Monjalon    # do the bind by writing to /sys
423c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/bind" % driver
424c6dab2a8SThomas Monjalon    try:
425c6dab2a8SThomas Monjalon        f = open(filename, "a")
42662d3ce60SStephen Hemminger    except OSError as err:
42762d3ce60SStephen Hemminger        print("Error: bind failed for %s - Cannot open %s: %s"
42862d3ce60SStephen Hemminger              % (dev_id, filename, err), file=sys.stderr)
429c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
430c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
431c6dab2a8SThomas Monjalon        return
432c6dab2a8SThomas Monjalon    try:
433c6dab2a8SThomas Monjalon        f.write(dev_id)
434c6dab2a8SThomas Monjalon        f.close()
43562d3ce60SStephen Hemminger    except OSError as err:
436c6dab2a8SThomas Monjalon        # for some reason, closing dev_id after adding a new PCI ID to new_id
437c6dab2a8SThomas Monjalon        # results in IOError. however, if the device was successfully bound,
438c6dab2a8SThomas Monjalon        # we don't care for any errors and can safely ignore IOError
439c3ce205dSGuduri Prathyusha        tmp = get_pci_device_details(dev_id, True)
440c6dab2a8SThomas Monjalon        if "Driver_str" in tmp and tmp["Driver_str"] == driver:
441c6dab2a8SThomas Monjalon            return
44262d3ce60SStephen Hemminger        print("Error: bind failed for %s - Cannot bind to driver %s: %s"
44362d3ce60SStephen Hemminger              % (dev_id, driver, err), file=sys.stderr)
444c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
445c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
446c6dab2a8SThomas Monjalon        return
447c6dab2a8SThomas Monjalon
448720b7a05SGuduri Prathyusha    # For kernels > 3.15 driver_override is used to bind a device to a driver.
449720b7a05SGuduri Prathyusha    # Before unbinding it, overwrite driver_override with empty string so that
450720b7a05SGuduri Prathyusha    # the device can be bound to any other driver
451720b7a05SGuduri Prathyusha    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
4521bb98a90SStephen Hemminger    if exists(filename):
453720b7a05SGuduri Prathyusha        try:
454720b7a05SGuduri Prathyusha            f = open(filename, "w")
45562d3ce60SStephen Hemminger        except OSError as err:
45662d3ce60SStephen Hemminger            sys.exit("Error: unbind failed for %s - Cannot open %s: %s"
45762d3ce60SStephen Hemminger                     % (dev_id, filename, err))
458720b7a05SGuduri Prathyusha        try:
459720b7a05SGuduri Prathyusha            f.write("\00")
460720b7a05SGuduri Prathyusha            f.close()
46162d3ce60SStephen Hemminger        except OSError as err:
46262d3ce60SStephen Hemminger            sys.exit("Error: unbind failed for %s - Cannot write %s: %s"
46362d3ce60SStephen Hemminger                     % (dev_id, filename, err))
464720b7a05SGuduri Prathyusha
465c6dab2a8SThomas Monjalon
466c6dab2a8SThomas Monjalondef unbind_all(dev_list, force=False):
467c6dab2a8SThomas Monjalon    """Unbind method, takes a list of device locations"""
468657c7133SFerruh Yigit
469657c7133SFerruh Yigit    if dev_list[0] == "dpdk":
470657c7133SFerruh Yigit        for d in devices.keys():
471657c7133SFerruh Yigit            if "Driver_str" in devices[d]:
472657c7133SFerruh Yigit                if devices[d]["Driver_str"] in dpdk_drivers:
473657c7133SFerruh Yigit                    unbind_one(devices[d]["Slot"], force)
474657c7133SFerruh Yigit        return
475657c7133SFerruh Yigit
47615f6aac7SAnatoly Burakov    try:
477c6dab2a8SThomas Monjalon        dev_list = map(dev_id_from_dev_name, dev_list)
47815f6aac7SAnatoly Burakov    except ValueError as ex:
47915f6aac7SAnatoly Burakov        print(ex)
48015f6aac7SAnatoly Burakov        sys.exit(1)
48115f6aac7SAnatoly Burakov
482c6dab2a8SThomas Monjalon    for d in dev_list:
483c6dab2a8SThomas Monjalon        unbind_one(d, force)
484c6dab2a8SThomas Monjalon
485c6dab2a8SThomas Monjalon
4866ca0f1c8SFidaullah Noonaridef has_iommu():
4876ca0f1c8SFidaullah Noonari    """Check if IOMMU is enabled on system"""
4886ca0f1c8SFidaullah Noonari    return len(os.listdir("/sys/class/iommu")) > 0
4896ca0f1c8SFidaullah Noonari
4906ca0f1c8SFidaullah Noonari
4916ca0f1c8SFidaullah Noonaridef check_noiommu_mode():
4926ca0f1c8SFidaullah Noonari    """Check and enable the noiommu mode for VFIO drivers"""
4936ca0f1c8SFidaullah Noonari    global noiommu_flag
4946ca0f1c8SFidaullah Noonari    filename = "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode"
4956ca0f1c8SFidaullah Noonari
4966ca0f1c8SFidaullah Noonari    try:
4976ca0f1c8SFidaullah Noonari        with open(filename, "r") as f:
498c77887adSRogelio Domínguez Hernández            value = f.read(1)
499c77887adSRogelio Domínguez Hernández            if value in ("1", "y" ,"Y"):
5006ca0f1c8SFidaullah Noonari                return
5016ca0f1c8SFidaullah Noonari    except OSError as err:
5026ca0f1c8SFidaullah Noonari        sys.exit(f"Error: failed to check unsafe noiommu mode - Cannot open {filename}: {err}")
5036ca0f1c8SFidaullah Noonari
5046ca0f1c8SFidaullah Noonari    if not noiommu_flag:
5056ca0f1c8SFidaullah Noonari        sys.exit("Error: IOMMU support is disabled, use --noiommu-mode for binding in noiommu mode")
5066ca0f1c8SFidaullah Noonari
5076ca0f1c8SFidaullah Noonari    try:
5086ca0f1c8SFidaullah Noonari        with open(filename, "w") as f:
5096ca0f1c8SFidaullah Noonari            f.write("1")
5106ca0f1c8SFidaullah Noonari    except OSError as err:
5116ca0f1c8SFidaullah Noonari        sys.exit(f"Error: failed to enable unsafe noiommu mode - Cannot open {filename}: {err}")
5126ca0f1c8SFidaullah Noonari    print("Warning: enabling unsafe no IOMMU mode for VFIO drivers")
5136ca0f1c8SFidaullah Noonari
5146ca0f1c8SFidaullah Noonari
515c6dab2a8SThomas Monjalondef bind_all(dev_list, driver, force=False):
516c6dab2a8SThomas Monjalon    """Bind method, takes a list of device locations"""
517c6dab2a8SThomas Monjalon    global devices
518c6dab2a8SThomas Monjalon
51915f6aac7SAnatoly Burakov    # a common user error is to forget to specify the driver the devices need to
52015f6aac7SAnatoly Burakov    # be bound to. check if the driver is a valid device, and if it is, show
52115f6aac7SAnatoly Burakov    # a meaningful error.
52215f6aac7SAnatoly Burakov    try:
52315f6aac7SAnatoly Burakov        dev_id_from_dev_name(driver)
52415f6aac7SAnatoly Burakov        # if we've made it this far, this means that the "driver" was a valid
52515f6aac7SAnatoly Burakov        # device string, so it's probably not a valid driver name.
52662d3ce60SStephen Hemminger        sys.exit("Error: Driver '%s' does not look like a valid driver. "
52715f6aac7SAnatoly Burakov                 "Did you forget to specify the driver to bind devices to?" % driver)
52815f6aac7SAnatoly Burakov    except ValueError:
52915f6aac7SAnatoly Burakov        # driver generated error - it's not a valid device ID, so all is well
53015f6aac7SAnatoly Burakov        pass
53115f6aac7SAnatoly Burakov
532681a6728SAnatoly Burakov    # check if we're attempting to bind to a driver that isn't loaded
53343623124SPavan Nikhilesh    if not module_is_loaded(driver.replace('-', '_')):
534681a6728SAnatoly Burakov        sys.exit("Error: Driver '%s' is not loaded." % driver)
535681a6728SAnatoly Burakov
53615f6aac7SAnatoly Burakov    try:
537c6dab2a8SThomas Monjalon        dev_list = map(dev_id_from_dev_name, dev_list)
53815f6aac7SAnatoly Burakov    except ValueError as ex:
53915f6aac7SAnatoly Burakov        sys.exit(ex)
540c6dab2a8SThomas Monjalon
5416ca0f1c8SFidaullah Noonari    # check for IOMMU support
5426ca0f1c8SFidaullah Noonari    if driver == "vfio-pci" and not has_iommu():
5436ca0f1c8SFidaullah Noonari        check_noiommu_mode()
5446ca0f1c8SFidaullah Noonari
545c6dab2a8SThomas Monjalon    for d in dev_list:
546c6dab2a8SThomas Monjalon        bind_one(d, driver, force)
547c6dab2a8SThomas Monjalon
548e4839614SPavel Shirshov    # For kernels < 3.15 when binding devices to a generic driver
5492fc35029SGuduri Prathyusha    # (i.e. one that doesn't have a PCI ID table) using new_id, some devices
5502fc35029SGuduri Prathyusha    # that are not bound to any other driver could be bound even if no one has
5512fc35029SGuduri Prathyusha    # asked them to. hence, we check the list of drivers again, and see if
5522fc35029SGuduri Prathyusha    # some of the previously-unbound devices were erroneously bound.
5531bb98a90SStephen Hemminger    if not exists("/sys/bus/pci/devices/%s/driver_override" % d):
554c6dab2a8SThomas Monjalon        for d in devices.keys():
555c6dab2a8SThomas Monjalon            # skip devices that were already bound or that we know should be bound
556c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d] or d in dev_list:
557c6dab2a8SThomas Monjalon                continue
558c6dab2a8SThomas Monjalon
559c6dab2a8SThomas Monjalon            # update information about this device
56062d3ce60SStephen Hemminger            devices[d] = dict(devices[d].items()
56162d3ce60SStephen Hemminger                              + get_pci_device_details(d, True).items())
562c6dab2a8SThomas Monjalon
563c6dab2a8SThomas Monjalon            # check if updated information indicates that the device was bound
564c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d]:
565c6dab2a8SThomas Monjalon                unbind_one(d, force)
566c6dab2a8SThomas Monjalon
567c6dab2a8SThomas Monjalon
568c6dab2a8SThomas Monjalondef display_devices(title, dev_list, extra_params=None):
569c6dab2a8SThomas Monjalon    '''Displays to the user the details of a list of devices given in
570c6dab2a8SThomas Monjalon    "dev_list". The "extra_params" parameter, if given, should contain a string
571c6dab2a8SThomas Monjalon     with %()s fields in it for replacement by the named fields in each
572c6dab2a8SThomas Monjalon     device's dictionary.'''
573c6dab2a8SThomas Monjalon    strings = []  # this holds the strings to print. We sort before printing
574c6dab2a8SThomas Monjalon    print("\n%s" % title)
575c6dab2a8SThomas Monjalon    print("=" * len(title))
576d58360c6SStephen Hemminger    if not dev_list:
577c6dab2a8SThomas Monjalon        strings.append("<none>")
578c6dab2a8SThomas Monjalon    else:
579c6dab2a8SThomas Monjalon        for dev in dev_list:
580c6dab2a8SThomas Monjalon            if extra_params is not None:
581c3ce205dSGuduri Prathyusha                strings.append("%s '%s %s' %s" % (dev["Slot"],
582c6dab2a8SThomas Monjalon                                                  dev["Device_str"],
583c3ce205dSGuduri Prathyusha                                                  dev["Device"],
584c6dab2a8SThomas Monjalon                                                  extra_params % dev))
585c6dab2a8SThomas Monjalon            else:
586c6dab2a8SThomas Monjalon                strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
587c6dab2a8SThomas Monjalon    # sort before printing, so that the entries appear in PCI order
588c6dab2a8SThomas Monjalon    strings.sort()
589c6dab2a8SThomas Monjalon    print("\n".join(strings))  # print one per line
590c6dab2a8SThomas Monjalon
59162d3ce60SStephen Hemminger
59236f66d1cSBruce Richardsondef show_device_status(devices_type, device_name, if_field=False):
593c6dab2a8SThomas Monjalon    global dpdk_drivers
594c6dab2a8SThomas Monjalon    kernel_drv = []
595c6dab2a8SThomas Monjalon    dpdk_drv = []
596c6dab2a8SThomas Monjalon    no_drv = []
597c6dab2a8SThomas Monjalon
598c6dab2a8SThomas Monjalon    # split our list of network devices into the three categories above
599c6dab2a8SThomas Monjalon    for d in devices.keys():
6008ad08a28SGuduri Prathyusha        if device_type_match(devices[d], devices_type):
601c6dab2a8SThomas Monjalon            if not has_driver(d):
602c6dab2a8SThomas Monjalon                no_drv.append(devices[d])
603c6dab2a8SThomas Monjalon                continue
604c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in dpdk_drivers:
605c6dab2a8SThomas Monjalon                dpdk_drv.append(devices[d])
606c6dab2a8SThomas Monjalon            else:
607c6dab2a8SThomas Monjalon                kernel_drv.append(devices[d])
608c6dab2a8SThomas Monjalon
609109cb989SAnatoly Burakov    n_devs = len(dpdk_drv) + len(kernel_drv) + len(no_drv)
610109cb989SAnatoly Burakov
611109cb989SAnatoly Burakov    # don't bother displaying anything if there are no devices
612109cb989SAnatoly Burakov    if n_devs == 0:
613109cb989SAnatoly Burakov        msg = "No '%s' devices detected" % device_name
614109cb989SAnatoly Burakov        print("")
615109cb989SAnatoly Burakov        print(msg)
616109cb989SAnatoly Burakov        print("".join('=' * len(msg)))
617109cb989SAnatoly Burakov        return
618109cb989SAnatoly Burakov
619*a7d69cefSAnatoly Burakov    print_numa = is_numa()
620*a7d69cefSAnatoly Burakov
621c6dab2a8SThomas Monjalon    # print each category separately, so we can clearly see what's used by DPDK
622d58360c6SStephen Hemminger    if dpdk_drv:
623*a7d69cefSAnatoly Burakov        extra_param = "drv=%(Driver_str)s unused=%(Module_str)s"
624*a7d69cefSAnatoly Burakov        if print_numa:
625*a7d69cefSAnatoly Burakov            extra_param = "numa_node=%(NUMANode)s " + extra_param
6268ad08a28SGuduri Prathyusha        display_devices("%s devices using DPDK-compatible driver" % device_name,
627*a7d69cefSAnatoly Burakov                        dpdk_drv, extra_param)
628d58360c6SStephen Hemminger    if kernel_drv:
629*a7d69cefSAnatoly Burakov        extra_param = "drv=%(Driver_str)s unused=%(Module_str)s"
63036f66d1cSBruce Richardson        if if_field:
631*a7d69cefSAnatoly Burakov            extra_param = "if=%(Interface)s " + extra_param
632*a7d69cefSAnatoly Burakov        if print_numa:
633*a7d69cefSAnatoly Burakov            extra_param = "numa_node=%(NUMANode)s " + extra_param
634*a7d69cefSAnatoly Burakov        display_devices("%s devices using kernel driver" % device_name,
635*a7d69cefSAnatoly Burakov                        kernel_drv, extra_param)
636d58360c6SStephen Hemminger    if no_drv:
637*a7d69cefSAnatoly Burakov        extra_param = "unused=%(Module_str)s"
638*a7d69cefSAnatoly Burakov        if print_numa:
639*a7d69cefSAnatoly Burakov            extra_param = "numa_node=%(NUMANode)s " + extra_param
640*a7d69cefSAnatoly Burakov        display_devices("Other %s devices" % device_name, no_drv, extra_param)
641c6dab2a8SThomas Monjalon
64262d3ce60SStephen Hemminger
643c7dd412bSGuduri Prathyushadef show_status():
644c7dd412bSGuduri Prathyusha    '''Function called when the script is passed the "--status" option.
645c7dd412bSGuduri Prathyusha    Displays to the user what devices are bound to the igb_uio driver, the
646c7dd412bSGuduri Prathyusha    kernel driver or to no driver'''
647c6dab2a8SThomas Monjalon
6480a3f92cdSStephen Hemminger    if status_dev in ["net", "all"]:
64936f66d1cSBruce Richardson        show_device_status(network_devices, "Network", if_field=True)
650b153c00bSFerruh Yigit
6510a3f92cdSStephen Hemminger    if status_dev in ["baseband", "all"]:
65207488e29SNicolas Chautru        show_device_status(baseband_devices, "Baseband")
65307488e29SNicolas Chautru
6540a3f92cdSStephen Hemminger    if status_dev in ["crypto", "all"]:
655c7dd412bSGuduri Prathyusha        show_device_status(crypto_devices, "Crypto")
656b153c00bSFerruh Yigit
6579afeef14SKevin Laatz    if status_dev in ["dma", "all"]:
6589afeef14SKevin Laatz        show_device_status(dma_devices, "DMA")
6599afeef14SKevin Laatz
6600a3f92cdSStephen Hemminger    if status_dev in ["event", "all"]:
66132a02dbfSGuduri Prathyusha        show_device_status(eventdev_devices, "Eventdev")
662b153c00bSFerruh Yigit
6630a3f92cdSStephen Hemminger    if status_dev in ["mempool", "all"]:
66480a1858dSGuduri Prathyusha        show_device_status(mempool_devices, "Mempool")
665c6dab2a8SThomas Monjalon
6660a3f92cdSStephen Hemminger    if status_dev in ["compress", "all"]:
6679d35895eSSunila Sahu        show_device_status(compress_devices, "Compress")
6689d35895eSSunila Sahu
6690a3f92cdSStephen Hemminger    if status_dev in ["misc", "all"]:
67012d4777aSBruce Richardson        show_device_status(misc_devices, "Misc (rawdev)")
6719d35895eSSunila Sahu
6720a3f92cdSStephen Hemminger    if status_dev in ["regex", "all"]:
67309f84c9aSGuy Kaneti        show_device_status(regex_devices, "Regex")
67409f84c9aSGuy Kaneti
675b9aaa675SSrikanth Yalavarthi    if status_dev in ["ml", "all"]:
676b9aaa675SSrikanth Yalavarthi        show_device_status(ml_devices, "ML")
677b9aaa675SSrikanth Yalavarthi
678781eafc9SBruce Richardson
679781eafc9SBruce Richardsondef pci_glob(arg):
680781eafc9SBruce Richardson    '''Returns a list containing either:
681781eafc9SBruce Richardson    * List of PCI B:D:F matching arg, using shell wildcards e.g. 80:04.*
682781eafc9SBruce Richardson    * Only the passed arg if matching list is empty'''
683781eafc9SBruce Richardson    sysfs_path = "/sys/bus/pci/devices"
684781eafc9SBruce Richardson    for _glob in [arg, '0000:' + arg]:
685781eafc9SBruce Richardson        paths = [basename(path) for path in glob(path_join(sysfs_path, _glob))]
686781eafc9SBruce Richardson        if paths:
687781eafc9SBruce Richardson            return paths
688781eafc9SBruce Richardson    return [arg]
689781eafc9SBruce Richardson
690781eafc9SBruce Richardson
691c6dab2a8SThomas Monjalondef parse_args():
692c6dab2a8SThomas Monjalon    '''Parses the command-line arguments given by the user and takes the
693c6dab2a8SThomas Monjalon    appropriate action for each'''
694c6dab2a8SThomas Monjalon    global b_flag
695c6dab2a8SThomas Monjalon    global status_flag
696b153c00bSFerruh Yigit    global status_dev
697c6dab2a8SThomas Monjalon    global force_flag
6986ca0f1c8SFidaullah Noonari    global noiommu_flag
699c6dab2a8SThomas Monjalon    global args
700c6dab2a8SThomas Monjalon
70181255f27SStephen Hemminger    parser = argparse.ArgumentParser(
70281255f27SStephen Hemminger        description='Utility to bind and unbind devices from Linux kernel',
70381255f27SStephen Hemminger        formatter_class=argparse.RawDescriptionHelpFormatter,
70481255f27SStephen Hemminger        epilog="""
70581255f27SStephen HemmingerExamples:
70681255f27SStephen Hemminger---------
707c6dab2a8SThomas Monjalon
70881255f27SStephen HemmingerTo display current device status:
70981255f27SStephen Hemminger        %(prog)s --status
71081255f27SStephen Hemminger
71181255f27SStephen HemmingerTo display current network device status:
71281255f27SStephen Hemminger        %(prog)s --status-dev net
71381255f27SStephen Hemminger
71481255f27SStephen HemmingerTo bind eth1 from the current driver and move to use vfio-pci
71581255f27SStephen Hemminger        %(prog)s --bind=vfio-pci eth1
71681255f27SStephen Hemminger
71781255f27SStephen HemmingerTo unbind 0000:01:00.0 from using any driver
71881255f27SStephen Hemminger        %(prog)s -u 0000:01:00.0
71981255f27SStephen Hemminger
72081255f27SStephen HemmingerTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
72181255f27SStephen Hemminger        %(prog)s -b ixgbe 02:00.0 02:00.1
72281255f27SStephen Hemminger""")
72381255f27SStephen Hemminger
72481255f27SStephen Hemminger    parser.add_argument(
72581255f27SStephen Hemminger        '-s',
72681255f27SStephen Hemminger        '--status',
72781255f27SStephen Hemminger        action='store_true',
72881255f27SStephen Hemminger        help="Print the current status of all known devices.")
72981255f27SStephen Hemminger    parser.add_argument(
73081255f27SStephen Hemminger        '--status-dev',
73181255f27SStephen Hemminger        help="Print the status of given device group.",
7329afeef14SKevin Laatz        choices=['baseband', 'compress', 'crypto', 'dma', 'event',
733b9aaa675SSrikanth Yalavarthi                 'mempool', 'misc', 'net', 'regex', 'ml'])
73481255f27SStephen Hemminger    bind_group = parser.add_mutually_exclusive_group()
73581255f27SStephen Hemminger    bind_group.add_argument(
73681255f27SStephen Hemminger        '-b',
73781255f27SStephen Hemminger        '--bind',
73881255f27SStephen Hemminger        metavar='DRIVER',
73981255f27SStephen Hemminger        help="Select the driver to use or \"none\" to unbind the device")
74081255f27SStephen Hemminger    bind_group.add_argument(
74181255f27SStephen Hemminger        '-u',
74281255f27SStephen Hemminger        '--unbind',
74381255f27SStephen Hemminger        action='store_true',
74481255f27SStephen Hemminger        help="Unbind a device (equivalent to \"-b none\")")
74581255f27SStephen Hemminger    parser.add_argument(
7466ca0f1c8SFidaullah Noonari        '--noiommu-mode',
7476ca0f1c8SFidaullah Noonari        action='store_true',
7486ca0f1c8SFidaullah Noonari        help="If IOMMU is not available, enable no IOMMU mode for VFIO drivers")
7496ca0f1c8SFidaullah Noonari    parser.add_argument(
75081255f27SStephen Hemminger        '--force',
75181255f27SStephen Hemminger        action='store_true',
75281255f27SStephen Hemminger        help="""
75381255f27SStephen HemmingerOverride restriction on binding devices in use by Linux"
75481255f27SStephen HemmingerWARNING: This can lead to loss of network connection and should be used with caution.
75581255f27SStephen Hemminger""")
75681255f27SStephen Hemminger    parser.add_argument(
75781255f27SStephen Hemminger        'devices',
75881255f27SStephen Hemminger        metavar='DEVICE',
75981255f27SStephen Hemminger        nargs='*',
76081255f27SStephen Hemminger        help="""
76181255f27SStephen HemmingerDevice specified as PCI "domain:bus:slot.func" syntax or "bus:slot.func" syntax.
76281255f27SStephen HemmingerFor devices bound to Linux kernel drivers, they may be referred to by interface name.
76381255f27SStephen Hemminger""")
76481255f27SStephen Hemminger
76581255f27SStephen Hemminger    opt = parser.parse_args()
76681255f27SStephen Hemminger
76781255f27SStephen Hemminger    if opt.status_dev:
768b153c00bSFerruh Yigit        status_flag = True
76981255f27SStephen Hemminger        status_dev = opt.status_dev
77081255f27SStephen Hemminger    if opt.status:
771c6dab2a8SThomas Monjalon        status_flag = True
772b153c00bSFerruh Yigit        status_dev = "all"
77381255f27SStephen Hemminger    if opt.force:
774c6dab2a8SThomas Monjalon        force_flag = True
7756ca0f1c8SFidaullah Noonari    if opt.noiommu_mode:
7766ca0f1c8SFidaullah Noonari        noiommu_flag = True
77781255f27SStephen Hemminger    if opt.bind:
77881255f27SStephen Hemminger        b_flag = opt.bind
77981255f27SStephen Hemminger    elif opt.unbind:
780c6dab2a8SThomas Monjalon        b_flag = "none"
78181255f27SStephen Hemminger    args = opt.devices
78281255f27SStephen Hemminger
78381255f27SStephen Hemminger    if not b_flag and not status_flag:
78481255f27SStephen Hemminger        print("Error: No action specified for devices. "
78581255f27SStephen Hemminger              "Please give a --bind, --ubind or --status option",
78681255f27SStephen Hemminger              file=sys.stderr)
78781255f27SStephen Hemminger        parser.print_usage()
78881255f27SStephen Hemminger        sys.exit(1)
78981255f27SStephen Hemminger
79081255f27SStephen Hemminger    if b_flag and not args:
79181255f27SStephen Hemminger        print("Error: No devices specified.", file=sys.stderr)
79281255f27SStephen Hemminger        parser.print_usage()
79381255f27SStephen Hemminger        sys.exit(1)
794c6dab2a8SThomas Monjalon
795781eafc9SBruce Richardson    # resolve any PCI globs in the args
796781eafc9SBruce Richardson    new_args = []
797781eafc9SBruce Richardson    for arg in args:
798781eafc9SBruce Richardson        new_args.extend(pci_glob(arg))
799781eafc9SBruce Richardson    args = new_args
800c6dab2a8SThomas Monjalon
80162d3ce60SStephen Hemminger
802c6dab2a8SThomas Monjalondef do_arg_actions():
803c6dab2a8SThomas Monjalon    '''do the actual action requested by the user'''
804c6dab2a8SThomas Monjalon    global b_flag
805c6dab2a8SThomas Monjalon    global status_flag
806c6dab2a8SThomas Monjalon    global force_flag
807c6dab2a8SThomas Monjalon    global args
808c6dab2a8SThomas Monjalon
8090a3f92cdSStephen Hemminger    if b_flag in ["none", "None"]:
810c6dab2a8SThomas Monjalon        unbind_all(args, force_flag)
811c6dab2a8SThomas Monjalon    elif b_flag is not None:
812c6dab2a8SThomas Monjalon        bind_all(args, b_flag, force_flag)
813c6dab2a8SThomas Monjalon    if status_flag:
814c6dab2a8SThomas Monjalon        if b_flag is not None:
815ea9f00f7SGuduri Prathyusha            clear_data()
8168ad08a28SGuduri Prathyusha            # refresh if we have changed anything
8178ad08a28SGuduri Prathyusha            get_device_details(network_devices)
81807488e29SNicolas Chautru            get_device_details(baseband_devices)
8198ad08a28SGuduri Prathyusha            get_device_details(crypto_devices)
8209afeef14SKevin Laatz            get_device_details(dma_devices)
82132a02dbfSGuduri Prathyusha            get_device_details(eventdev_devices)
82280a1858dSGuduri Prathyusha            get_device_details(mempool_devices)
8239d35895eSSunila Sahu            get_device_details(compress_devices)
82409f84c9aSGuy Kaneti            get_device_details(regex_devices)
825b9aaa675SSrikanth Yalavarthi            get_device_details(ml_devices)
82612d4777aSBruce Richardson            get_device_details(misc_devices)
827c6dab2a8SThomas Monjalon        show_status()
828c6dab2a8SThomas Monjalon
829c6dab2a8SThomas Monjalon
830c6dab2a8SThomas Monjalondef main():
831c6dab2a8SThomas Monjalon    '''program main function'''
8321a5a9cb3SAnatoly Burakov    # check if lspci is installed, suppress any output
8331a5a9cb3SAnatoly Burakov    with open(os.devnull, 'w') as devnull:
8341a5a9cb3SAnatoly Burakov        ret = subprocess.call(['which', 'lspci'],
8351a5a9cb3SAnatoly Burakov                              stdout=devnull, stderr=devnull)
8361a5a9cb3SAnatoly Burakov        if ret != 0:
8372804529fSAnatoly Burakov            sys.exit("'lspci' not found - please install 'pciutils'")
838c6dab2a8SThomas Monjalon    parse_args()
839c6dab2a8SThomas Monjalon    check_modules()
840ea9f00f7SGuduri Prathyusha    clear_data()
8418ad08a28SGuduri Prathyusha    get_device_details(network_devices)
84207488e29SNicolas Chautru    get_device_details(baseband_devices)
8438ad08a28SGuduri Prathyusha    get_device_details(crypto_devices)
8449afeef14SKevin Laatz    get_device_details(dma_devices)
84532a02dbfSGuduri Prathyusha    get_device_details(eventdev_devices)
84680a1858dSGuduri Prathyusha    get_device_details(mempool_devices)
8479d35895eSSunila Sahu    get_device_details(compress_devices)
84809f84c9aSGuy Kaneti    get_device_details(regex_devices)
849b9aaa675SSrikanth Yalavarthi    get_device_details(ml_devices)
85012d4777aSBruce Richardson    get_device_details(misc_devices)
851c6dab2a8SThomas Monjalon    do_arg_actions()
852c6dab2a8SThomas Monjalon
85362d3ce60SStephen Hemminger
854c6dab2a8SThomas Monjalonif __name__ == "__main__":
855c6dab2a8SThomas Monjalon    main()
856