xref: /dpdk/usertools/dpdk-devbind.py (revision 43f9b521a7ea441bfe79a524b52d3e48077821db)
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 getopt
9c6dab2a8SThomas Monjalonimport subprocess
10781eafc9SBruce Richardsonfrom glob import glob
11c6dab2a8SThomas Monjalonfrom os.path import exists, abspath, dirname, basename
12781eafc9SBruce Richardsonfrom os.path import join as path_join
13c6dab2a8SThomas Monjalon
148ad08a28SGuduri Prathyusha# The PCI base class for all devices
158ad08a28SGuduri Prathyushanetwork_class = {'Class': '02', 'Vendor': None, 'Device': None,
168ad08a28SGuduri Prathyusha                    'SVendor': None, 'SDevice': None}
1707488e29SNicolas Chautruacceleration_class = {'Class': '12', 'Vendor': None, 'Device': None,
1807488e29SNicolas Chautru                      'SVendor': None, 'SDevice': None}
19c01c748eSRosen Xuifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30',
20c01c748eSRosen Xu                    'SVendor': None, 'SDevice': None}
218ad08a28SGuduri Prathyushaencryption_class = {'Class': '10', 'Vendor': None, 'Device': None,
228ad08a28SGuduri Prathyusha                   'SVendor': None, 'SDevice': None}
238ad08a28SGuduri Prathyushaintel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,
248ad08a28SGuduri Prathyusha                   'SVendor': None, 'SDevice': None}
2532a02dbfSGuduri Prathyushacavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d',
2632a02dbfSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
2780a1858dSGuduri Prathyushacavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053',
2880a1858dSGuduri Prathyusha              'SVendor': None, 'SDevice': None}
29156c42eaSJerin Jacobcavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049',
30156c42eaSJerin Jacob              'SVendor': None, 'SDevice': None}
31f4bc0010SPavan Nikhileshcavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051',
32f4bc0010SPavan Nikhilesh              'SVendor': None, 'SDevice': None}
339d35895eSSunila Sahucavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037',
349d35895eSSunila Sahu              'SVendor': None, 'SDevice': None}
3520526313SXiaohua Zhangavp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110',
3620526313SXiaohua Zhang              'SVendor': None, 'SDevice': None}
378ad08a28SGuduri Prathyusha
380bcc6644SJerin Jacobocteontx2_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f9,a0fa',
390bcc6644SJerin Jacob              'SVendor': None, 'SDevice': None}
400bcc6644SJerin Jacobocteontx2_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc',
410bcc6644SJerin Jacob              'SVendor': None, 'SDevice': None}
42f5be5d99SJerin Jacobocteontx2_dma = {'Class': '08', 'Vendor': '177d', 'Device': 'a081',
43f5be5d99SJerin Jacob              'SVendor': None, 'SDevice': None}
440bcc6644SJerin Jacob
4512d4777aSBruce Richardsonintel_ioat_bdw = {'Class': '08', 'Vendor': '8086', 'Device': '6f20,6f21,6f22,6f23,6f24,6f25,6f26,6f27,6f2e,6f2f',
4612d4777aSBruce Richardson              'SVendor': None, 'SDevice': None}
4712d4777aSBruce Richardsonintel_ioat_skx = {'Class': '08', 'Vendor': '8086', 'Device': '2021',
4812d4777aSBruce Richardson              'SVendor': None, 'SDevice': None}
49299e282fSRadu Nicolauintel_ioat_icx = {'Class': '08', 'Vendor': '8086', 'Device': '0b00',
50299e282fSRadu Nicolau              'SVendor': None, 'SDevice': None}
51*43f9b521SKevin Laatzintel_idxd_spr = {'Class': '08', 'Vendor': '8086', 'Device': '0b25',
52*43f9b521SKevin Laatz              'SVendor': None, 'SDevice': None}
53034c328eSXiaoyun Liintel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c',
54034c328eSXiaoyun Li              'SVendor': None, 'SDevice': None}
55f5057be3SXiaoyun Liintel_ntb_icx = {'Class': '06', 'Vendor': '8086', 'Device': '347e',
56f5057be3SXiaoyun Li              'SVendor': None, 'SDevice': None}
5712d4777aSBruce Richardson
58c01c748eSRosen Xunetwork_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
5907488e29SNicolas Chautrubaseband_devices = [acceleration_class]
608ad08a28SGuduri Prathyushacrypto_devices = [encryption_class, intel_processor_class]
610bcc6644SJerin Jacobeventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso]
620bcc6644SJerin Jacobmempool_devices = [cavium_fpa, octeontx2_npa]
639d35895eSSunila Sahucompress_devices = [cavium_zip]
64*43f9b521SKevin Laatzmisc_devices = [intel_ioat_bdw, intel_ioat_skx, intel_ioat_icx, intel_idxd_spr,
65*43f9b521SKevin Laatz                intel_ntb_skx, intel_ntb_icx,
66*43f9b521SKevin Laatz                octeontx2_dma]
67c6dab2a8SThomas Monjalon
68c6dab2a8SThomas Monjalon# global dict ethernet devices present. Dictionary indexed by PCI address.
69c6dab2a8SThomas Monjalon# Each device within this is itself a dictionary of device properties
70c6dab2a8SThomas Monjalondevices = {}
71c6dab2a8SThomas Monjalon# list of supported DPDK drivers
72c6dab2a8SThomas Monjalondpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"]
73681a6728SAnatoly Burakov# list of currently loaded kernel modules
74681a6728SAnatoly Burakovloaded_modules = None
75c6dab2a8SThomas Monjalon
76c6dab2a8SThomas Monjalon# command-line arg flags
77c6dab2a8SThomas Monjalonb_flag = None
78c6dab2a8SThomas Monjalonstatus_flag = False
79c6dab2a8SThomas Monjalonforce_flag = False
80c6dab2a8SThomas Monjalonargs = []
81c6dab2a8SThomas Monjalon
82c6dab2a8SThomas Monjalon
83c6dab2a8SThomas Monjalondef usage():
84c6dab2a8SThomas Monjalon    '''Print usage information for the program'''
85c6dab2a8SThomas Monjalon    argv0 = basename(sys.argv[0])
86c6dab2a8SThomas Monjalon    print("""
87c6dab2a8SThomas MonjalonUsage:
88c6dab2a8SThomas Monjalon------
89c6dab2a8SThomas Monjalon
90c6dab2a8SThomas Monjalon     %(argv0)s [options] DEVICE1 DEVICE2 ....
91c6dab2a8SThomas Monjalon
92c6dab2a8SThomas Monjalonwhere DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax
93c6dab2a8SThomas Monjalonor "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may
94c6dab2a8SThomas Monjalonalso be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc.
95781eafc9SBruce RichardsonIf devices are specified using PCI <domain:>bus:device:func format, then
96781eafc9SBruce Richardsonshell wildcards and ranges may be used, e.g. 80:04.*, 80:04.[0-3]
97c6dab2a8SThomas Monjalon
98c6dab2a8SThomas MonjalonOptions:
99c6dab2a8SThomas Monjalon    --help, --usage:
100c6dab2a8SThomas Monjalon        Display usage information and quit
101c6dab2a8SThomas Monjalon
102c6dab2a8SThomas Monjalon    -s, --status:
103b153c00bSFerruh Yigit        Print the current status of all known network, crypto, event
104b153c00bSFerruh Yigit        and mempool devices.
105c6dab2a8SThomas Monjalon        For each device, it displays the PCI domain, bus, slot and function,
106c6dab2a8SThomas Monjalon        along with a text description of the device. Depending upon whether the
107c6dab2a8SThomas Monjalon        device is being used by a kernel driver, the igb_uio driver, or no
108c6dab2a8SThomas Monjalon        driver, other relevant information will be displayed:
109c6dab2a8SThomas Monjalon        * the Linux interface name e.g. if=eth0
110c6dab2a8SThomas Monjalon        * the driver being used e.g. drv=igb_uio
111c6dab2a8SThomas Monjalon        * any suitable drivers not currently using that device
112c6dab2a8SThomas Monjalon            e.g. unused=igb_uio
113c6dab2a8SThomas Monjalon        NOTE: if this flag is passed along with a bind/unbind option, the
114c6dab2a8SThomas Monjalon        status display will always occur after the other operations have taken
115c6dab2a8SThomas Monjalon        place.
116c6dab2a8SThomas Monjalon
117b153c00bSFerruh Yigit    --status-dev:
118b153c00bSFerruh Yigit        Print the status of given device group. Supported device groups are:
11907488e29SNicolas Chautru        "net", "baseband", "crypto", "event", "mempool" and "compress"
120b153c00bSFerruh Yigit
121c6dab2a8SThomas Monjalon    -b driver, --bind=driver:
122c6dab2a8SThomas Monjalon        Select the driver to use or \"none\" to unbind the device
123c6dab2a8SThomas Monjalon
124c6dab2a8SThomas Monjalon    -u, --unbind:
125c6dab2a8SThomas Monjalon        Unbind a device (Equivalent to \"-b none\")
126c6dab2a8SThomas Monjalon
127c6dab2a8SThomas Monjalon    --force:
128c6dab2a8SThomas Monjalon        By default, network devices which are used by Linux - as indicated by
129c6dab2a8SThomas Monjalon        having routes in the routing table - cannot be modified. Using the
130c6dab2a8SThomas Monjalon        --force flag overrides this behavior, allowing active links to be
131c6dab2a8SThomas Monjalon        forcibly unbound.
132c6dab2a8SThomas Monjalon        WARNING: This can lead to loss of network connection and should be used
133c6dab2a8SThomas Monjalon        with caution.
134c6dab2a8SThomas Monjalon
135c6dab2a8SThomas MonjalonExamples:
136c6dab2a8SThomas Monjalon---------
137c6dab2a8SThomas Monjalon
138c6dab2a8SThomas MonjalonTo display current device status:
139c6dab2a8SThomas Monjalon        %(argv0)s --status
140c6dab2a8SThomas Monjalon
141b153c00bSFerruh YigitTo display current network device status:
142b153c00bSFerruh Yigit        %(argv0)s --status-dev net
143b153c00bSFerruh Yigit
144c6dab2a8SThomas MonjalonTo bind eth1 from the current driver and move to use igb_uio
145c6dab2a8SThomas Monjalon        %(argv0)s --bind=igb_uio eth1
146c6dab2a8SThomas Monjalon
147c6dab2a8SThomas MonjalonTo unbind 0000:01:00.0 from using any driver
148c6dab2a8SThomas Monjalon        %(argv0)s -u 0000:01:00.0
149c6dab2a8SThomas Monjalon
150c6dab2a8SThomas MonjalonTo bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver
151c6dab2a8SThomas Monjalon        %(argv0)s -b ixgbe 02:00.0 02:00.1
152c6dab2a8SThomas Monjalon
153781eafc9SBruce RichardsonTo bind all functions on device 0000:02:00 to ixgbe kernel driver
154781eafc9SBruce Richardson        %(argv0)s -b ixgbe 02:00.*
155781eafc9SBruce Richardson
156c6dab2a8SThomas Monjalon    """ % locals())  # replace items from local variables
157c6dab2a8SThomas Monjalon
158681a6728SAnatoly Burakov# check if a specific kernel module is loaded
159681a6728SAnatoly Burakovdef module_is_loaded(module):
160681a6728SAnatoly Burakov    global loaded_modules
161681a6728SAnatoly Burakov
16243623124SPavan Nikhilesh    if module == 'vfio_pci':
16343623124SPavan Nikhilesh        module = 'vfio-pci'
16443623124SPavan Nikhilesh
165681a6728SAnatoly Burakov    if loaded_modules:
166681a6728SAnatoly Burakov        return module in loaded_modules
167681a6728SAnatoly Burakov
168681a6728SAnatoly Burakov    # Get list of sysfs modules (both built-in and dynamically loaded)
169681a6728SAnatoly Burakov    sysfs_path = '/sys/module/'
170681a6728SAnatoly Burakov
171681a6728SAnatoly Burakov    # Get the list of directories in sysfs_path
172681a6728SAnatoly Burakov    sysfs_mods = [m for m in os.listdir(sysfs_path)
173681a6728SAnatoly Burakov                  if os.path.isdir(os.path.join(sysfs_path, m))]
174681a6728SAnatoly Burakov
175681a6728SAnatoly Burakov    # special case for vfio_pci (module is named vfio-pci,
176681a6728SAnatoly Burakov    # but its .ko is named vfio_pci)
177681a6728SAnatoly Burakov    sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods]
178681a6728SAnatoly Burakov
179681a6728SAnatoly Burakov    loaded_modules = sysfs_mods
180681a6728SAnatoly Burakov
181681a6728SAnatoly Burakov    return module in sysfs_mods
182681a6728SAnatoly Burakov
183c6dab2a8SThomas Monjalon
184c6dab2a8SThomas Monjalondef check_modules():
185c6dab2a8SThomas Monjalon    '''Checks that igb_uio is loaded'''
186c6dab2a8SThomas Monjalon    global dpdk_drivers
187c6dab2a8SThomas Monjalon
188c6dab2a8SThomas Monjalon    # list of supported modules
189c6dab2a8SThomas Monjalon    mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers]
190c6dab2a8SThomas Monjalon
191c6dab2a8SThomas Monjalon    # first check if module is loaded
192c6dab2a8SThomas Monjalon    for mod in mods:
193681a6728SAnatoly Burakov        if module_is_loaded(mod["Name"]):
194c6dab2a8SThomas Monjalon            mod["Found"] = True
195c6dab2a8SThomas Monjalon
196c6dab2a8SThomas Monjalon    # check if we have at least one loaded module
197c6dab2a8SThomas Monjalon    if True not in [mod["Found"] for mod in mods] and b_flag is not None:
1982804529fSAnatoly Burakov        print("Warning: no supported DPDK kernel modules are loaded", file=sys.stderr)
199c6dab2a8SThomas Monjalon
200c6dab2a8SThomas Monjalon    # change DPDK driver list to only contain drivers that are loaded
201c6dab2a8SThomas Monjalon    dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]]
202c6dab2a8SThomas Monjalon
203c6dab2a8SThomas Monjalon
204c6dab2a8SThomas Monjalondef has_driver(dev_id):
205c6dab2a8SThomas Monjalon    '''return true if a device is assigned to a driver. False otherwise'''
206c6dab2a8SThomas Monjalon    return "Driver_str" in devices[dev_id]
207c6dab2a8SThomas Monjalon
208c6dab2a8SThomas Monjalon
209c3ce205dSGuduri Prathyushadef get_pci_device_details(dev_id, probe_lspci):
210c6dab2a8SThomas Monjalon    '''This function gets additional details for a PCI device'''
211c6dab2a8SThomas Monjalon    device = {}
212c6dab2a8SThomas Monjalon
213c3ce205dSGuduri Prathyusha    if probe_lspci:
2143f6f8362SLouise Kilheeney        extra_info = subprocess.check_output(["lspci", "-vmmks", dev_id]).splitlines()
215c6dab2a8SThomas Monjalon        # parse lspci details
216c6dab2a8SThomas Monjalon        for line in extra_info:
217c6dab2a8SThomas Monjalon            if len(line) == 0:
218c6dab2a8SThomas Monjalon                continue
21908ab6cd3SChristos Ricudis            name, value = line.decode("utf8").split("\t", 1)
220c6dab2a8SThomas Monjalon            name = name.strip(":") + "_str"
221c6dab2a8SThomas Monjalon            device[name] = value
222c6dab2a8SThomas Monjalon    # check for a unix interface name
223c6dab2a8SThomas Monjalon    device["Interface"] = ""
224c6dab2a8SThomas Monjalon    for base, dirs, _ in os.walk("/sys/bus/pci/devices/%s/" % dev_id):
225c6dab2a8SThomas Monjalon        if "net" in dirs:
226c6dab2a8SThomas Monjalon            device["Interface"] = \
227c6dab2a8SThomas Monjalon                ",".join(os.listdir(os.path.join(base, "net")))
228c6dab2a8SThomas Monjalon            break
229c6dab2a8SThomas Monjalon    # check if a port is used for ssh connection
230c6dab2a8SThomas Monjalon    device["Ssh_if"] = False
231c6dab2a8SThomas Monjalon    device["Active"] = ""
232c6dab2a8SThomas Monjalon
233c6dab2a8SThomas Monjalon    return device
234c6dab2a8SThomas Monjalon
235ea9f00f7SGuduri Prathyushadef clear_data():
236ea9f00f7SGuduri Prathyusha    '''This function clears any old data'''
23793b93bebSTimothy Redaelli    global devices
238ea9f00f7SGuduri Prathyusha    devices = {}
239c6dab2a8SThomas Monjalon
240ea9f00f7SGuduri Prathyushadef get_device_details(devices_type):
241c6dab2a8SThomas Monjalon    '''This function populates the "devices" dictionary. The keys used are
242c6dab2a8SThomas Monjalon    the pci addresses (domain:bus:slot.func). The values are themselves
243c6dab2a8SThomas Monjalon    dictionaries - one for each NIC.'''
244c6dab2a8SThomas Monjalon    global devices
245c6dab2a8SThomas Monjalon    global dpdk_drivers
246c6dab2a8SThomas Monjalon
247c6dab2a8SThomas Monjalon    # first loop through and read details for all devices
248c3ce205dSGuduri Prathyusha    # request machine readable format, with numeric IDs and String
249c6dab2a8SThomas Monjalon    dev = {}
2503f6f8362SLouise Kilheeney    dev_lines = subprocess.check_output(["lspci", "-Dvmmnnk"]).splitlines()
251c6dab2a8SThomas Monjalon    for dev_line in dev_lines:
252c6dab2a8SThomas Monjalon        if len(dev_line) == 0:
2538ad08a28SGuduri Prathyusha            if device_type_match(dev, devices_type):
2548ad08a28SGuduri Prathyusha                # Replace "Driver" with "Driver_str" to have consistency of
2558ad08a28SGuduri Prathyusha                # of dictionary key names
256c3ce205dSGuduri Prathyusha                if "Driver" in dev.keys():
257c3ce205dSGuduri Prathyusha                    dev["Driver_str"] = dev.pop("Driver")
258c76a10ecSAnatoly Burakov                if "Module" in dev.keys():
259c76a10ecSAnatoly Burakov                    dev["Module_str"] = dev.pop("Module")
260c6dab2a8SThomas Monjalon                # use dict to make copy of dev
261c6dab2a8SThomas Monjalon                devices[dev["Slot"]] = dict(dev)
262c3ce205dSGuduri Prathyusha            # Clear previous device's data
263c3ce205dSGuduri Prathyusha            dev = {}
264c6dab2a8SThomas Monjalon        else:
26508ab6cd3SChristos Ricudis            name, value = dev_line.decode("utf8").split("\t", 1)
266c3ce205dSGuduri Prathyusha            value_list = value.rsplit(' ', 1)
267c3ce205dSGuduri Prathyusha            if len(value_list) > 1:
268c3ce205dSGuduri Prathyusha                # String stored in <name>_str
269c3ce205dSGuduri Prathyusha                dev[name.rstrip(":") + '_str'] = value_list[0]
270c3ce205dSGuduri Prathyusha            # Numeric IDs
271c3ce205dSGuduri Prathyusha            dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
272c3ce205dSGuduri Prathyusha                .rstrip("]").lstrip("[")
273c6dab2a8SThomas Monjalon
2748ad08a28SGuduri Prathyusha    if devices_type == network_devices:
275c6dab2a8SThomas Monjalon        # check what is the interface if any for an ssh connection if
276c6dab2a8SThomas Monjalon        # any to this host, so we can mark it later.
277c6dab2a8SThomas Monjalon        ssh_if = []
2783f6f8362SLouise Kilheeney        route = subprocess.check_output(["ip", "-o", "route"])
279c6dab2a8SThomas Monjalon        # filter out all lines for 169.254 routes
280c6dab2a8SThomas Monjalon        route = "\n".join(filter(lambda ln: not ln.startswith("169.254"),
281c6dab2a8SThomas Monjalon                             route.decode().splitlines()))
282c6dab2a8SThomas Monjalon        rt_info = route.split()
283c6dab2a8SThomas Monjalon        for i in range(len(rt_info) - 1):
284c6dab2a8SThomas Monjalon            if rt_info[i] == "dev":
285c6dab2a8SThomas Monjalon                ssh_if.append(rt_info[i+1])
286c6dab2a8SThomas Monjalon
287c6dab2a8SThomas Monjalon    # based on the basic info, get extended text details
288c6dab2a8SThomas Monjalon    for d in devices.keys():
2898ad08a28SGuduri Prathyusha        if not device_type_match(devices[d], devices_type):
290617d9052SYoni Gilad            continue
291617d9052SYoni Gilad
292c6dab2a8SThomas Monjalon        # get additional info and add it to existing data
293c6dab2a8SThomas Monjalon        devices[d] = devices[d].copy()
294c3ce205dSGuduri Prathyusha        # No need to probe lspci
295c3ce205dSGuduri Prathyusha        devices[d].update(get_pci_device_details(d, False).items())
296c6dab2a8SThomas Monjalon
2978ad08a28SGuduri Prathyusha        if devices_type == network_devices:
298ea9f00f7SGuduri Prathyusha            for _if in ssh_if:
299ea9f00f7SGuduri Prathyusha                if _if in devices[d]["Interface"].split(","):
300ea9f00f7SGuduri Prathyusha                    devices[d]["Ssh_if"] = True
301ea9f00f7SGuduri Prathyusha                    devices[d]["Active"] = "*Active*"
302ea9f00f7SGuduri Prathyusha                    break
303ea9f00f7SGuduri Prathyusha
304c6dab2a8SThomas Monjalon        # add igb_uio to list of supporting modules if needed
305c6dab2a8SThomas Monjalon        if "Module_str" in devices[d]:
306c6dab2a8SThomas Monjalon            for driver in dpdk_drivers:
307c6dab2a8SThomas Monjalon                if driver not in devices[d]["Module_str"]:
308c6dab2a8SThomas Monjalon                    devices[d]["Module_str"] = \
309c6dab2a8SThomas Monjalon                        devices[d]["Module_str"] + ",%s" % driver
310c6dab2a8SThomas Monjalon        else:
311c6dab2a8SThomas Monjalon            devices[d]["Module_str"] = ",".join(dpdk_drivers)
312c6dab2a8SThomas Monjalon
313c6dab2a8SThomas Monjalon        # make sure the driver and module strings do not have any duplicates
314c6dab2a8SThomas Monjalon        if has_driver(d):
315c6dab2a8SThomas Monjalon            modules = devices[d]["Module_str"].split(",")
316c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in modules:
317c6dab2a8SThomas Monjalon                modules.remove(devices[d]["Driver_str"])
318c6dab2a8SThomas Monjalon                devices[d]["Module_str"] = ",".join(modules)
319c6dab2a8SThomas Monjalon
320c6dab2a8SThomas Monjalon
3218ad08a28SGuduri Prathyushadef device_type_match(dev, devices_type):
3228ad08a28SGuduri Prathyusha    for i in range(len(devices_type)):
3238ad08a28SGuduri Prathyusha        param_count = len(
3248ad08a28SGuduri Prathyusha            [x for x in devices_type[i].values() if x is not None])
3258ad08a28SGuduri Prathyusha        match_count = 0
3268ad08a28SGuduri Prathyusha        if dev["Class"][0:2] == devices_type[i]["Class"]:
3278ad08a28SGuduri Prathyusha            match_count = match_count + 1
3288ad08a28SGuduri Prathyusha            for key in devices_type[i].keys():
3298ad08a28SGuduri Prathyusha                if key != 'Class' and devices_type[i][key]:
3308ad08a28SGuduri Prathyusha                    value_list = devices_type[i][key].split(',')
3318ad08a28SGuduri Prathyusha                    for value in value_list:
3328ad08a28SGuduri Prathyusha                        if value.strip(' ') == dev[key]:
3338ad08a28SGuduri Prathyusha                            match_count = match_count + 1
3348ad08a28SGuduri Prathyusha            # count must be the number of non None parameters to match
3358ad08a28SGuduri Prathyusha            if match_count == param_count:
3368ad08a28SGuduri Prathyusha                return True
3378ad08a28SGuduri Prathyusha    return False
3388ad08a28SGuduri Prathyusha
339c6dab2a8SThomas Monjalondef dev_id_from_dev_name(dev_name):
340c6dab2a8SThomas Monjalon    '''Take a device "name" - a string passed in by user to identify a NIC
341c6dab2a8SThomas Monjalon    device, and determine the device id - i.e. the domain:bus:slot.func - for
342c6dab2a8SThomas Monjalon    it, which can then be used to index into the devices array'''
343c6dab2a8SThomas Monjalon
344c6dab2a8SThomas Monjalon    # check if it's already a suitable index
345c6dab2a8SThomas Monjalon    if dev_name in devices:
346c6dab2a8SThomas Monjalon        return dev_name
347c6dab2a8SThomas Monjalon    # check if it's an index just missing the domain part
348c6dab2a8SThomas Monjalon    elif "0000:" + dev_name in devices:
349c6dab2a8SThomas Monjalon        return "0000:" + dev_name
350c6dab2a8SThomas Monjalon    else:
351c6dab2a8SThomas Monjalon        # check if it's an interface name, e.g. eth1
352c6dab2a8SThomas Monjalon        for d in devices.keys():
353c6dab2a8SThomas Monjalon            if dev_name in devices[d]["Interface"].split(","):
354c6dab2a8SThomas Monjalon                return devices[d]["Slot"]
355c6dab2a8SThomas Monjalon    # if nothing else matches - error
35615f6aac7SAnatoly Burakov    raise ValueError("Unknown device: %s. "
357c6dab2a8SThomas Monjalon                     "Please specify device in \"bus:slot.func\" format" % dev_name)
358c6dab2a8SThomas Monjalon
359c6dab2a8SThomas Monjalon
360c6dab2a8SThomas Monjalondef unbind_one(dev_id, force):
361c6dab2a8SThomas Monjalon    '''Unbind the device identified by "dev_id" from its current driver'''
362c6dab2a8SThomas Monjalon    dev = devices[dev_id]
363c6dab2a8SThomas Monjalon    if not has_driver(dev_id):
3642804529fSAnatoly Burakov        print("Notice: %s %s %s is not currently managed by any driver" %
3652804529fSAnatoly Burakov              (dev["Slot"], dev["Device_str"], dev["Interface"]), file=sys.stderr)
366c6dab2a8SThomas Monjalon        return
367c6dab2a8SThomas Monjalon
368c6dab2a8SThomas Monjalon    # prevent us disconnecting ourselves
369c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
3702804529fSAnatoly Burakov        print("Warning: routing table indicates that interface %s is active. "
3712804529fSAnatoly Burakov              "Skipping unbind" % dev_id, file=sys.stderr)
372c6dab2a8SThomas Monjalon        return
373c6dab2a8SThomas Monjalon
374c6dab2a8SThomas Monjalon    # write to /sys to unbind
375c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
376c6dab2a8SThomas Monjalon    try:
377c6dab2a8SThomas Monjalon        f = open(filename, "a")
378c6dab2a8SThomas Monjalon    except:
3792804529fSAnatoly Burakov        sys.exit("Error: unbind failed for %s - Cannot open %s" %
3802804529fSAnatoly Burakov                 (dev_id, filename))
381c6dab2a8SThomas Monjalon    f.write(dev_id)
382c6dab2a8SThomas Monjalon    f.close()
383c6dab2a8SThomas Monjalon
384c6dab2a8SThomas Monjalon
385c6dab2a8SThomas Monjalondef bind_one(dev_id, driver, force):
386c6dab2a8SThomas Monjalon    '''Bind the device given by "dev_id" to the driver "driver". If the device
387c6dab2a8SThomas Monjalon    is already bound to a different driver, it will be unbound first'''
388c6dab2a8SThomas Monjalon    dev = devices[dev_id]
389c6dab2a8SThomas Monjalon    saved_driver = None  # used to rollback any unbind in case of failure
390c6dab2a8SThomas Monjalon
391c6dab2a8SThomas Monjalon    # prevent disconnection of our ssh session
392c6dab2a8SThomas Monjalon    if dev["Ssh_if"] and not force:
3932804529fSAnatoly Burakov        print("Warning: routing table indicates that interface %s is active. "
3942804529fSAnatoly Burakov              "Not modifying" % dev_id, file=sys.stderr)
395c6dab2a8SThomas Monjalon        return
396c6dab2a8SThomas Monjalon
397c6dab2a8SThomas Monjalon    # unbind any existing drivers we don't want
398c6dab2a8SThomas Monjalon    if has_driver(dev_id):
399c6dab2a8SThomas Monjalon        if dev["Driver_str"] == driver:
4002804529fSAnatoly Burakov            print("Notice: %s already bound to driver %s, skipping" %
4012804529fSAnatoly Burakov                  (dev_id, driver), file=sys.stderr)
402c6dab2a8SThomas Monjalon            return
403c6dab2a8SThomas Monjalon        else:
404c6dab2a8SThomas Monjalon            saved_driver = dev["Driver_str"]
405c6dab2a8SThomas Monjalon            unbind_one(dev_id, force)
406c6dab2a8SThomas Monjalon            dev["Driver_str"] = ""  # clear driver string
407c6dab2a8SThomas Monjalon
4082fc35029SGuduri Prathyusha    # For kernels >= 3.15 driver_override can be used to specify the driver
4092fc35029SGuduri Prathyusha    # for a device rather than relying on the driver to provide a positive
4102fc35029SGuduri Prathyusha    # match of the device.  The existing process of looking up
4112fc35029SGuduri Prathyusha    # the vendor and device ID, adding them to the driver new_id,
4122fc35029SGuduri Prathyusha    # will erroneously bind other devices too which has the additional burden
4132fc35029SGuduri Prathyusha    # of unbinding those devices
414c6dab2a8SThomas Monjalon    if driver in dpdk_drivers:
4152fc35029SGuduri Prathyusha        filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
4162fc35029SGuduri Prathyusha        if os.path.exists(filename):
4172fc35029SGuduri Prathyusha            try:
4182fc35029SGuduri Prathyusha                f = open(filename, "w")
4192fc35029SGuduri Prathyusha            except:
4202fc35029SGuduri Prathyusha                print("Error: bind failed for %s - Cannot open %s"
4212804529fSAnatoly Burakov                      % (dev_id, filename), file=sys.stderr)
4222fc35029SGuduri Prathyusha                return
4232fc35029SGuduri Prathyusha            try:
4242fc35029SGuduri Prathyusha                f.write("%s" % driver)
4252fc35029SGuduri Prathyusha                f.close()
4262fc35029SGuduri Prathyusha            except:
4272fc35029SGuduri Prathyusha                print("Error: bind failed for %s - Cannot write driver %s to "
4282804529fSAnatoly Burakov                      "PCI ID " % (dev_id, driver), file=sys.stderr)
4292fc35029SGuduri Prathyusha                return
4302fc35029SGuduri Prathyusha        # For kernels < 3.15 use new_id to add PCI id's to the driver
4312fc35029SGuduri Prathyusha        else:
432c6dab2a8SThomas Monjalon            filename = "/sys/bus/pci/drivers/%s/new_id" % driver
433c6dab2a8SThomas Monjalon            try:
434c6dab2a8SThomas Monjalon                f = open(filename, "w")
435c6dab2a8SThomas Monjalon            except:
436c6dab2a8SThomas Monjalon                print("Error: bind failed for %s - Cannot open %s"
4372804529fSAnatoly Burakov                      % (dev_id, filename), file=sys.stderr)
438c6dab2a8SThomas Monjalon                return
439c6dab2a8SThomas Monjalon            try:
4408ad08a28SGuduri Prathyusha                # Convert Device and Vendor Id to int to write to new_id
4418ad08a28SGuduri Prathyusha                f.write("%04x %04x" % (int(dev["Vendor"],16),
4428ad08a28SGuduri Prathyusha                        int(dev["Device"], 16)))
443c6dab2a8SThomas Monjalon                f.close()
444c6dab2a8SThomas Monjalon            except:
445c6dab2a8SThomas Monjalon                print("Error: bind failed for %s - Cannot write new PCI ID to "
4462804529fSAnatoly Burakov                      "driver %s" % (dev_id, driver), file=sys.stderr)
447c6dab2a8SThomas Monjalon                return
448c6dab2a8SThomas Monjalon
449c6dab2a8SThomas Monjalon    # do the bind by writing to /sys
450c6dab2a8SThomas Monjalon    filename = "/sys/bus/pci/drivers/%s/bind" % driver
451c6dab2a8SThomas Monjalon    try:
452c6dab2a8SThomas Monjalon        f = open(filename, "a")
453c6dab2a8SThomas Monjalon    except:
454c6dab2a8SThomas Monjalon        print("Error: bind failed for %s - Cannot open %s"
4552804529fSAnatoly Burakov              % (dev_id, filename), file=sys.stderr)
456c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
457c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
458c6dab2a8SThomas Monjalon        return
459c6dab2a8SThomas Monjalon    try:
460c6dab2a8SThomas Monjalon        f.write(dev_id)
461c6dab2a8SThomas Monjalon        f.close()
462c6dab2a8SThomas Monjalon    except:
463c6dab2a8SThomas Monjalon        # for some reason, closing dev_id after adding a new PCI ID to new_id
464c6dab2a8SThomas Monjalon        # results in IOError. however, if the device was successfully bound,
465c6dab2a8SThomas Monjalon        # we don't care for any errors and can safely ignore IOError
466c3ce205dSGuduri Prathyusha        tmp = get_pci_device_details(dev_id, True)
467c6dab2a8SThomas Monjalon        if "Driver_str" in tmp and tmp["Driver_str"] == driver:
468c6dab2a8SThomas Monjalon            return
469c6dab2a8SThomas Monjalon        print("Error: bind failed for %s - Cannot bind to driver %s"
4702804529fSAnatoly Burakov              % (dev_id, driver), file=sys.stderr)
471c6dab2a8SThomas Monjalon        if saved_driver is not None:  # restore any previous driver
472c6dab2a8SThomas Monjalon            bind_one(dev_id, saved_driver, force)
473c6dab2a8SThomas Monjalon        return
474c6dab2a8SThomas Monjalon
475720b7a05SGuduri Prathyusha    # For kernels > 3.15 driver_override is used to bind a device to a driver.
476720b7a05SGuduri Prathyusha    # Before unbinding it, overwrite driver_override with empty string so that
477720b7a05SGuduri Prathyusha    # the device can be bound to any other driver
478720b7a05SGuduri Prathyusha    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
479720b7a05SGuduri Prathyusha    if os.path.exists(filename):
480720b7a05SGuduri Prathyusha        try:
481720b7a05SGuduri Prathyusha            f = open(filename, "w")
482720b7a05SGuduri Prathyusha        except:
4832804529fSAnatoly Burakov            sys.exit("Error: unbind failed for %s - Cannot open %s"
484720b7a05SGuduri Prathyusha                  % (dev_id, filename))
485720b7a05SGuduri Prathyusha        try:
486720b7a05SGuduri Prathyusha            f.write("\00")
487720b7a05SGuduri Prathyusha            f.close()
488720b7a05SGuduri Prathyusha        except:
4892804529fSAnatoly Burakov            sys.exit("Error: unbind failed for %s - Cannot open %s"
490720b7a05SGuduri Prathyusha                  % (dev_id, filename))
491720b7a05SGuduri Prathyusha
492c6dab2a8SThomas Monjalon
493c6dab2a8SThomas Monjalondef unbind_all(dev_list, force=False):
494c6dab2a8SThomas Monjalon    """Unbind method, takes a list of device locations"""
495657c7133SFerruh Yigit
496657c7133SFerruh Yigit    if dev_list[0] == "dpdk":
497657c7133SFerruh Yigit        for d in devices.keys():
498657c7133SFerruh Yigit            if "Driver_str" in devices[d]:
499657c7133SFerruh Yigit                if devices[d]["Driver_str"] in dpdk_drivers:
500657c7133SFerruh Yigit                    unbind_one(devices[d]["Slot"], force)
501657c7133SFerruh Yigit        return
502657c7133SFerruh Yigit
50315f6aac7SAnatoly Burakov    try:
504c6dab2a8SThomas Monjalon        dev_list = map(dev_id_from_dev_name, dev_list)
50515f6aac7SAnatoly Burakov    except ValueError as ex:
50615f6aac7SAnatoly Burakov        print(ex)
50715f6aac7SAnatoly Burakov        sys.exit(1)
50815f6aac7SAnatoly Burakov
509c6dab2a8SThomas Monjalon    for d in dev_list:
510c6dab2a8SThomas Monjalon        unbind_one(d, force)
511c6dab2a8SThomas Monjalon
512c6dab2a8SThomas Monjalon
513c6dab2a8SThomas Monjalondef bind_all(dev_list, driver, force=False):
514c6dab2a8SThomas Monjalon    """Bind method, takes a list of device locations"""
515c6dab2a8SThomas Monjalon    global devices
516c6dab2a8SThomas Monjalon
51715f6aac7SAnatoly Burakov    # a common user error is to forget to specify the driver the devices need to
51815f6aac7SAnatoly Burakov    # be bound to. check if the driver is a valid device, and if it is, show
51915f6aac7SAnatoly Burakov    # a meaningful error.
52015f6aac7SAnatoly Burakov    try:
52115f6aac7SAnatoly Burakov        dev_id_from_dev_name(driver)
52215f6aac7SAnatoly Burakov        # if we've made it this far, this means that the "driver" was a valid
52315f6aac7SAnatoly Burakov        # device string, so it's probably not a valid driver name.
52415f6aac7SAnatoly Burakov        sys.exit("Error: Driver '%s' does not look like a valid driver. " \
52515f6aac7SAnatoly Burakov                 "Did you forget to specify the driver to bind devices to?" % driver)
52615f6aac7SAnatoly Burakov    except ValueError:
52715f6aac7SAnatoly Burakov        # driver generated error - it's not a valid device ID, so all is well
52815f6aac7SAnatoly Burakov        pass
52915f6aac7SAnatoly Burakov
530681a6728SAnatoly Burakov    # check if we're attempting to bind to a driver that isn't loaded
53143623124SPavan Nikhilesh    if not module_is_loaded(driver.replace('-','_')):
532681a6728SAnatoly Burakov        sys.exit("Error: Driver '%s' is not loaded." % driver)
533681a6728SAnatoly Burakov
53415f6aac7SAnatoly Burakov    try:
535c6dab2a8SThomas Monjalon        dev_list = map(dev_id_from_dev_name, dev_list)
53615f6aac7SAnatoly Burakov    except ValueError as ex:
53715f6aac7SAnatoly Burakov        sys.exit(ex)
538c6dab2a8SThomas Monjalon
539c6dab2a8SThomas Monjalon    for d in dev_list:
540c6dab2a8SThomas Monjalon        bind_one(d, driver, force)
541c6dab2a8SThomas Monjalon
542e4839614SPavel Shirshov    # For kernels < 3.15 when binding devices to a generic driver
5432fc35029SGuduri Prathyusha    # (i.e. one that doesn't have a PCI ID table) using new_id, some devices
5442fc35029SGuduri Prathyusha    # that are not bound to any other driver could be bound even if no one has
5452fc35029SGuduri Prathyusha    # asked them to. hence, we check the list of drivers again, and see if
5462fc35029SGuduri Prathyusha    # some of the previously-unbound devices were erroneously bound.
5472fc35029SGuduri Prathyusha    if not os.path.exists("/sys/bus/pci/devices/%s/driver_override" % d):
548c6dab2a8SThomas Monjalon        for d in devices.keys():
549c6dab2a8SThomas Monjalon            # skip devices that were already bound or that we know should be bound
550c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d] or d in dev_list:
551c6dab2a8SThomas Monjalon                continue
552c6dab2a8SThomas Monjalon
553c6dab2a8SThomas Monjalon            # update information about this device
554c6dab2a8SThomas Monjalon            devices[d] = dict(devices[d].items() +
555c3ce205dSGuduri Prathyusha                              get_pci_device_details(d, True).items())
556c6dab2a8SThomas Monjalon
557c6dab2a8SThomas Monjalon            # check if updated information indicates that the device was bound
558c6dab2a8SThomas Monjalon            if "Driver_str" in devices[d]:
559c6dab2a8SThomas Monjalon                unbind_one(d, force)
560c6dab2a8SThomas Monjalon
561c6dab2a8SThomas Monjalon
562c6dab2a8SThomas Monjalondef display_devices(title, dev_list, extra_params=None):
563c6dab2a8SThomas Monjalon    '''Displays to the user the details of a list of devices given in
564c6dab2a8SThomas Monjalon    "dev_list". The "extra_params" parameter, if given, should contain a string
565c6dab2a8SThomas Monjalon     with %()s fields in it for replacement by the named fields in each
566c6dab2a8SThomas Monjalon     device's dictionary.'''
567c6dab2a8SThomas Monjalon    strings = []  # this holds the strings to print. We sort before printing
568c6dab2a8SThomas Monjalon    print("\n%s" % title)
569c6dab2a8SThomas Monjalon    print("="*len(title))
570c6dab2a8SThomas Monjalon    if len(dev_list) == 0:
571c6dab2a8SThomas Monjalon        strings.append("<none>")
572c6dab2a8SThomas Monjalon    else:
573c6dab2a8SThomas Monjalon        for dev in dev_list:
574c6dab2a8SThomas Monjalon            if extra_params is not None:
575c3ce205dSGuduri Prathyusha                strings.append("%s '%s %s' %s" % (dev["Slot"],
576c6dab2a8SThomas Monjalon                                               dev["Device_str"],
577c3ce205dSGuduri Prathyusha                                               dev["Device"],
578c6dab2a8SThomas Monjalon                                               extra_params % dev))
579c6dab2a8SThomas Monjalon            else:
580c6dab2a8SThomas Monjalon                strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"]))
581c6dab2a8SThomas Monjalon    # sort before printing, so that the entries appear in PCI order
582c6dab2a8SThomas Monjalon    strings.sort()
583c6dab2a8SThomas Monjalon    print("\n".join(strings))  # print one per line
584c6dab2a8SThomas Monjalon
58536f66d1cSBruce Richardsondef show_device_status(devices_type, device_name, if_field=False):
586c6dab2a8SThomas Monjalon    global dpdk_drivers
587c6dab2a8SThomas Monjalon    kernel_drv = []
588c6dab2a8SThomas Monjalon    dpdk_drv = []
589c6dab2a8SThomas Monjalon    no_drv = []
590c6dab2a8SThomas Monjalon
591c6dab2a8SThomas Monjalon    # split our list of network devices into the three categories above
592c6dab2a8SThomas Monjalon    for d in devices.keys():
5938ad08a28SGuduri Prathyusha        if device_type_match(devices[d], devices_type):
594c6dab2a8SThomas Monjalon            if not has_driver(d):
595c6dab2a8SThomas Monjalon                no_drv.append(devices[d])
596c6dab2a8SThomas Monjalon                continue
597c6dab2a8SThomas Monjalon            if devices[d]["Driver_str"] in dpdk_drivers:
598c6dab2a8SThomas Monjalon                dpdk_drv.append(devices[d])
599c6dab2a8SThomas Monjalon            else:
600c6dab2a8SThomas Monjalon                kernel_drv.append(devices[d])
601c6dab2a8SThomas Monjalon
602109cb989SAnatoly Burakov    n_devs = len(dpdk_drv) + len(kernel_drv) + len(no_drv)
603109cb989SAnatoly Burakov
604109cb989SAnatoly Burakov    # don't bother displaying anything if there are no devices
605109cb989SAnatoly Burakov    if n_devs == 0:
606109cb989SAnatoly Burakov        msg = "No '%s' devices detected" % device_name
607109cb989SAnatoly Burakov        print("")
608109cb989SAnatoly Burakov        print(msg)
609109cb989SAnatoly Burakov        print("".join('=' * len(msg)))
610109cb989SAnatoly Burakov        return
611109cb989SAnatoly Burakov
612c6dab2a8SThomas Monjalon    # print each category separately, so we can clearly see what's used by DPDK
613109cb989SAnatoly Burakov    if len(dpdk_drv) != 0:
6148ad08a28SGuduri Prathyusha        display_devices("%s devices using DPDK-compatible driver" % device_name,
6158ad08a28SGuduri Prathyusha                        dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s")
616109cb989SAnatoly Burakov    if len(kernel_drv) != 0:
61736f66d1cSBruce Richardson        if_text = ""
61836f66d1cSBruce Richardson        if if_field:
61936f66d1cSBruce Richardson            if_text = "if=%(Interface)s "
620c7dd412bSGuduri Prathyusha        display_devices("%s devices using kernel driver" % device_name, kernel_drv,
62136f66d1cSBruce Richardson                        if_text + "drv=%(Driver_str)s "
622c6dab2a8SThomas Monjalon                        "unused=%(Module_str)s %(Active)s")
623109cb989SAnatoly Burakov    if len(no_drv) != 0:
6248ad08a28SGuduri Prathyusha        display_devices("Other %s devices" % device_name, no_drv,
6258ad08a28SGuduri Prathyusha                        "unused=%(Module_str)s")
626c6dab2a8SThomas Monjalon
627c7dd412bSGuduri Prathyushadef show_status():
628c7dd412bSGuduri Prathyusha    '''Function called when the script is passed the "--status" option.
629c7dd412bSGuduri Prathyusha    Displays to the user what devices are bound to the igb_uio driver, the
630c7dd412bSGuduri Prathyusha    kernel driver or to no driver'''
631c6dab2a8SThomas Monjalon
632b153c00bSFerruh Yigit    if status_dev == "net" or status_dev == "all":
63336f66d1cSBruce Richardson        show_device_status(network_devices, "Network", if_field=True)
634b153c00bSFerruh Yigit
63507488e29SNicolas Chautru    if status_dev == "baseband" or status_dev == "all":
63607488e29SNicolas Chautru        show_device_status(baseband_devices, "Baseband")
63707488e29SNicolas Chautru
638b153c00bSFerruh Yigit    if status_dev == "crypto" or status_dev == "all":
639c7dd412bSGuduri Prathyusha        show_device_status(crypto_devices, "Crypto")
640b153c00bSFerruh Yigit
641b153c00bSFerruh Yigit    if status_dev == "event" or status_dev == "all":
64232a02dbfSGuduri Prathyusha        show_device_status(eventdev_devices, "Eventdev")
643b153c00bSFerruh Yigit
644b153c00bSFerruh Yigit    if status_dev == "mempool" or status_dev == "all":
64580a1858dSGuduri Prathyusha        show_device_status(mempool_devices, "Mempool")
646c6dab2a8SThomas Monjalon
6479d35895eSSunila Sahu    if status_dev == "compress" or status_dev == "all":
6489d35895eSSunila Sahu        show_device_status(compress_devices , "Compress")
6499d35895eSSunila Sahu
65012d4777aSBruce Richardson    if status_dev == "misc" or status_dev == "all":
65112d4777aSBruce Richardson        show_device_status(misc_devices, "Misc (rawdev)")
6529d35895eSSunila Sahu
653781eafc9SBruce Richardson
654781eafc9SBruce Richardsondef pci_glob(arg):
655781eafc9SBruce Richardson    '''Returns a list containing either:
656781eafc9SBruce Richardson    * List of PCI B:D:F matching arg, using shell wildcards e.g. 80:04.*
657781eafc9SBruce Richardson    * Only the passed arg if matching list is empty'''
658781eafc9SBruce Richardson    sysfs_path = "/sys/bus/pci/devices"
659781eafc9SBruce Richardson    for _glob in [arg, '0000:' + arg]:
660781eafc9SBruce Richardson        paths = [basename(path) for path in glob(path_join(sysfs_path, _glob))]
661781eafc9SBruce Richardson        if paths:
662781eafc9SBruce Richardson            return paths
663781eafc9SBruce Richardson    return [arg]
664781eafc9SBruce Richardson
665781eafc9SBruce Richardson
666c6dab2a8SThomas Monjalondef parse_args():
667c6dab2a8SThomas Monjalon    '''Parses the command-line arguments given by the user and takes the
668c6dab2a8SThomas Monjalon    appropriate action for each'''
669c6dab2a8SThomas Monjalon    global b_flag
670c6dab2a8SThomas Monjalon    global status_flag
671b153c00bSFerruh Yigit    global status_dev
672c6dab2a8SThomas Monjalon    global force_flag
673c6dab2a8SThomas Monjalon    global args
674c6dab2a8SThomas Monjalon    if len(sys.argv) <= 1:
675c6dab2a8SThomas Monjalon        usage()
676c6dab2a8SThomas Monjalon        sys.exit(0)
677c6dab2a8SThomas Monjalon
678c6dab2a8SThomas Monjalon    try:
679c6dab2a8SThomas Monjalon        opts, args = getopt.getopt(sys.argv[1:], "b:us",
680b153c00bSFerruh Yigit                                   ["help", "usage", "status", "status-dev=",
681b153c00bSFerruh Yigit                                    "force", "bind=", "unbind", ])
682c6dab2a8SThomas Monjalon    except getopt.GetoptError as error:
683c6dab2a8SThomas Monjalon        print(str(error))
684c6dab2a8SThomas Monjalon        print("Run '%s --usage' for further information" % sys.argv[0])
685c6dab2a8SThomas Monjalon        sys.exit(1)
686c6dab2a8SThomas Monjalon
687c6dab2a8SThomas Monjalon    for opt, arg in opts:
688c6dab2a8SThomas Monjalon        if opt == "--help" or opt == "--usage":
689c6dab2a8SThomas Monjalon            usage()
690c6dab2a8SThomas Monjalon            sys.exit(0)
691b153c00bSFerruh Yigit        if opt == "--status-dev":
692b153c00bSFerruh Yigit            status_flag = True
693b153c00bSFerruh Yigit            status_dev = arg
694c6dab2a8SThomas Monjalon        if opt == "--status" or opt == "-s":
695c6dab2a8SThomas Monjalon            status_flag = True
696b153c00bSFerruh Yigit            status_dev = "all"
697c6dab2a8SThomas Monjalon        if opt == "--force":
698c6dab2a8SThomas Monjalon            force_flag = True
699c6dab2a8SThomas Monjalon        if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind":
700c6dab2a8SThomas Monjalon            if b_flag is not None:
7012804529fSAnatoly Burakov                sys.exit("Error: binding and unbinding are mutually exclusive")
702c6dab2a8SThomas Monjalon            if opt == "-u" or opt == "--unbind":
703c6dab2a8SThomas Monjalon                b_flag = "none"
704c6dab2a8SThomas Monjalon            else:
705c6dab2a8SThomas Monjalon                b_flag = arg
706c6dab2a8SThomas Monjalon
707781eafc9SBruce Richardson    # resolve any PCI globs in the args
708781eafc9SBruce Richardson    new_args = []
709781eafc9SBruce Richardson    for arg in args:
710781eafc9SBruce Richardson        new_args.extend(pci_glob(arg))
711781eafc9SBruce Richardson    args = new_args
712c6dab2a8SThomas Monjalon
713c6dab2a8SThomas Monjalondef do_arg_actions():
714c6dab2a8SThomas Monjalon    '''do the actual action requested by the user'''
715c6dab2a8SThomas Monjalon    global b_flag
716c6dab2a8SThomas Monjalon    global status_flag
717c6dab2a8SThomas Monjalon    global force_flag
718c6dab2a8SThomas Monjalon    global args
719c6dab2a8SThomas Monjalon
720c6dab2a8SThomas Monjalon    if b_flag is None and not status_flag:
721c6dab2a8SThomas Monjalon        print("Error: No action specified for devices. "
7222804529fSAnatoly Burakov              "Please give a -b or -u option", file=sys.stderr)
7232804529fSAnatoly Burakov        usage()
724c6dab2a8SThomas Monjalon        sys.exit(1)
725c6dab2a8SThomas Monjalon
726c6dab2a8SThomas Monjalon    if b_flag is not None and len(args) == 0:
7272804529fSAnatoly Burakov        print("Error: No devices specified.", file=sys.stderr)
7282804529fSAnatoly Burakov        usage()
729c6dab2a8SThomas Monjalon        sys.exit(1)
730c6dab2a8SThomas Monjalon
731c6dab2a8SThomas Monjalon    if b_flag == "none" or b_flag == "None":
732c6dab2a8SThomas Monjalon        unbind_all(args, force_flag)
733c6dab2a8SThomas Monjalon    elif b_flag is not None:
734c6dab2a8SThomas Monjalon        bind_all(args, b_flag, force_flag)
735c6dab2a8SThomas Monjalon    if status_flag:
736c6dab2a8SThomas Monjalon        if b_flag is not None:
737ea9f00f7SGuduri Prathyusha            clear_data()
7388ad08a28SGuduri Prathyusha            # refresh if we have changed anything
7398ad08a28SGuduri Prathyusha            get_device_details(network_devices)
74007488e29SNicolas Chautru            get_device_details(baseband_devices)
7418ad08a28SGuduri Prathyusha            get_device_details(crypto_devices)
74232a02dbfSGuduri Prathyusha            get_device_details(eventdev_devices)
74380a1858dSGuduri Prathyusha            get_device_details(mempool_devices)
7449d35895eSSunila Sahu            get_device_details(compress_devices)
74512d4777aSBruce Richardson            get_device_details(misc_devices)
746c6dab2a8SThomas Monjalon        show_status()
747c6dab2a8SThomas Monjalon
748c6dab2a8SThomas Monjalon
749c6dab2a8SThomas Monjalondef main():
750c6dab2a8SThomas Monjalon    '''program main function'''
7511a5a9cb3SAnatoly Burakov    # check if lspci is installed, suppress any output
7521a5a9cb3SAnatoly Burakov    with open(os.devnull, 'w') as devnull:
7531a5a9cb3SAnatoly Burakov        ret = subprocess.call(['which', 'lspci'],
7541a5a9cb3SAnatoly Burakov                              stdout=devnull, stderr=devnull)
7551a5a9cb3SAnatoly Burakov        if ret != 0:
7562804529fSAnatoly Burakov            sys.exit("'lspci' not found - please install 'pciutils'")
757c6dab2a8SThomas Monjalon    parse_args()
758c6dab2a8SThomas Monjalon    check_modules()
759ea9f00f7SGuduri Prathyusha    clear_data()
7608ad08a28SGuduri Prathyusha    get_device_details(network_devices)
76107488e29SNicolas Chautru    get_device_details(baseband_devices)
7628ad08a28SGuduri Prathyusha    get_device_details(crypto_devices)
76332a02dbfSGuduri Prathyusha    get_device_details(eventdev_devices)
76480a1858dSGuduri Prathyusha    get_device_details(mempool_devices)
7659d35895eSSunila Sahu    get_device_details(compress_devices)
76612d4777aSBruce Richardson    get_device_details(misc_devices)
767c6dab2a8SThomas Monjalon    do_arg_actions()
768c6dab2a8SThomas Monjalon
769c6dab2a8SThomas Monjalonif __name__ == "__main__":
770c6dab2a8SThomas Monjalon    main()
771