tools: use SPDX tag for Intel copyright files
[dpdk.git] / usertools / dpdk-devbind.py
index 4dc6a66..894b519 100755 (executable)
@@ -1,35 +1,6 @@
 #! /usr/bin/env python
-#
-#   BSD LICENSE
-#
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
-#   All rights reserved.
-#
-#   Redistribution and use in source and binary forms, with or without
-#   modification, are permitted provided that the following conditions
-#   are met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in
-#       the documentation and/or other materials provided with the
-#       distribution.
-#     * Neither the name of Intel Corporation nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
 #
 
 import sys
@@ -38,9 +9,24 @@ import getopt
 import subprocess
 from os.path import exists, abspath, dirname, basename
 
-# The PCI base class for NETWORK devices
-NETWORK_BASE_CLASS = "02"
-CRYPTO_BASE_CLASS = "0b"
+# The PCI base class for all devices
+network_class = {'Class': '02', 'Vendor': None, 'Device': None,
+                    'SVendor': None, 'SDevice': None}
+encryption_class = {'Class': '10', 'Vendor': None, 'Device': None,
+                   'SVendor': None, 'SDevice': None}
+intel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,
+                   'SVendor': None, 'SDevice': None}
+cavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d',
+              'SVendor': None, 'SDevice': None}
+cavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053',
+              'SVendor': None, 'SDevice': None}
+cavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049',
+              'SVendor': None, 'SDevice': None}
+
+network_devices = [network_class, cavium_pkx]
+crypto_devices = [encryption_class, intel_processor_class]
+eventdev_devices = [cavium_sso]
+mempool_devices = [cavium_fpa]
 
 # global dict ethernet devices present. Dictionary indexed by PCI address.
 # Each device within this is itself a dictionary of device properties
@@ -73,7 +59,8 @@ Options:
         Display usage information and quit
 
     -s, --status:
-        Print the current status of all known network and crypto devices.
+        Print the current status of all known network, crypto, event
+        and mempool devices.
         For each device, it displays the PCI domain, bus, slot and function,
         along with a text description of the device. Depending upon whether the
         device is being used by a kernel driver, the igb_uio driver, or no
@@ -86,6 +73,10 @@ Options:
         status display will always occur after the other operations have taken
         place.
 
+    --status-dev:
+        Print the status of given device group. Supported device groups are:
+        "net", "crypto", "event" and "mempool"
+
     -b driver, --bind=driver:
         Select the driver to use or \"none\" to unbind the device
 
@@ -106,6 +97,9 @@ Examples:
 To display current device status:
         %(argv0)s --status
 
+To display current network device status:
+        %(argv0)s --status-dev net
+
 To bind eth1 from the current driver and move to use igb_uio
         %(argv0)s --bind=igb_uio eth1
 
@@ -140,12 +134,11 @@ def find_module(mod):
 
     # check using depmod
     try:
-        depmod_out = check_output(["modinfo", "-n", mod],
-                                  stderr=subprocess.STDOUT).lower()
-        if "error" not in depmod_out:
-            path = depmod_out.strip()
-            if exists(path):
-                return path
+        with open(os.devnull, "w") as fnull:
+            path = check_output(["modinfo", "-n", mod], stderr=fnull).strip()
+
+        if path and exists(path):
+            return path
     except:  # if modinfo can't find module, it fails, so continue
         pass
 
@@ -182,8 +175,7 @@ def check_modules():
 
         # special case for vfio_pci (module is named vfio-pci,
         # but its .ko is named vfio_pci)
-        sysfs_mods = map(lambda a:
-                         a if a != 'vfio_pci' else 'vfio-pci', sysfs_mods)
+        sysfs_mods = [a if a != 'vfio_pci' else 'vfio-pci' for a in sysfs_mods]
 
         for mod in mods:
             if mod["Name"] in sysfs_mods:
@@ -252,10 +244,9 @@ def get_device_details(devices_type):
     dev_lines = check_output(["lspci", "-Dvmmnnk"]).splitlines()
     for dev_line in dev_lines:
         if len(dev_line) == 0:
-            if dev["Class"][0:2] == devices_type:
-                # convert device and vendor ids to numbers, then add to global
-                dev["Vendor"] = int(dev["Vendor"], 16)
-                dev["Device"] = int(dev["Device"], 16)
+            if device_type_match(dev, devices_type):
+                # Replace "Driver" with "Driver_str" to have consistency of
+                # of dictionary key names
                 if "Driver" in dev.keys():
                     dev["Driver_str"] = dev.pop("Driver")
                 # use dict to make copy of dev
@@ -272,7 +263,7 @@ def get_device_details(devices_type):
             dev[name.rstrip(":")] = value_list[len(value_list) - 1] \
                 .rstrip("]").lstrip("[")
 
-    if devices_type == NETWORK_BASE_CLASS:
+    if devices_type == network_devices:
         # check what is the interface if any for an ssh connection if
         # any to this host, so we can mark it later.
         ssh_if = []
@@ -287,7 +278,7 @@ def get_device_details(devices_type):
 
     # based on the basic info, get extended text details
     for d in devices.keys():
-        if devices[d]["Class"][0:2] != devices_type:
+        if not device_type_match(devices[d], devices_type):
             continue
 
         # get additional info and add it to existing data
@@ -295,7 +286,7 @@ def get_device_details(devices_type):
         # No need to probe lspci
         devices[d].update(get_pci_device_details(d, False).items())
 
-        if devices_type == NETWORK_BASE_CLASS:
+        if devices_type == network_devices:
             for _if in ssh_if:
                 if _if in devices[d]["Interface"].split(","):
                     devices[d]["Ssh_if"] = True
@@ -319,6 +310,24 @@ def get_device_details(devices_type):
                 devices[d]["Module_str"] = ",".join(modules)
 
 
+def device_type_match(dev, devices_type):
+    for i in range(len(devices_type)):
+        param_count = len(
+            [x for x in devices_type[i].values() if x is not None])
+        match_count = 0
+        if dev["Class"][0:2] == devices_type[i]["Class"]:
+            match_count = match_count + 1
+            for key in devices_type[i].keys():
+                if key != 'Class' and devices_type[i][key]:
+                    value_list = devices_type[i][key].split(',')
+                    for value in value_list:
+                        if value.strip(' ') == dev[key]:
+                            match_count = match_count + 1
+            # count must be the number of non None parameters to match
+            if match_count == param_count:
+                return True
+    return False
+
 def dev_id_from_dev_name(dev_name):
     '''Take a device "name" - a string passed in by user to identify a NIC
     device, and determine the device id - i.e. the domain:bus:slot.func - for
@@ -355,25 +364,6 @@ def unbind_one(dev_id, force):
               "Skipping unbind" % (dev_id))
         return
 
-    # For kernels > 3.15 driver_override is used to bind a device to a driver.
-    # Before unbinding it, overwrite driver_override with empty string so that
-    # the device can be bound to any other driver
-    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
-    if os.path.exists(filename):
-        try:
-            f = open(filename, "w")
-        except:
-            print("Error: unbind failed for %s - Cannot open %s"
-                  % (dev_id, filename))
-            sys.exit(1)
-        try:
-            f.write("\00")
-            f.close()
-        except:
-            print("Error: unbind failed for %s - Cannot open %s"
-                  % (dev_id, filename))
-            sys.exit(1)
-
     # write to /sys to unbind
     filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"]
     try:
@@ -441,7 +431,9 @@ def bind_one(dev_id, driver, force):
                       % (dev_id, filename))
                 return
             try:
-                f.write("%04x %04x" % (dev["Vendor"], dev["Device"]))
+                # Convert Device and Vendor Id to int to write to new_id
+                f.write("%04x %04x" % (int(dev["Vendor"],16),
+                        int(dev["Device"], 16)))
                 f.close()
             except:
                 print("Error: bind failed for %s - Cannot write new PCI ID to "
@@ -474,9 +466,36 @@ def bind_one(dev_id, driver, force):
             bind_one(dev_id, saved_driver, force)
         return
 
+    # For kernels > 3.15 driver_override is used to bind a device to a driver.
+    # Before unbinding it, overwrite driver_override with empty string so that
+    # the device can be bound to any other driver
+    filename = "/sys/bus/pci/devices/%s/driver_override" % dev_id
+    if os.path.exists(filename):
+        try:
+            f = open(filename, "w")
+        except:
+            print("Error: unbind failed for %s - Cannot open %s"
+                  % (dev_id, filename))
+            sys.exit(1)
+        try:
+            f.write("\00")
+            f.close()
+        except:
+            print("Error: unbind failed for %s - Cannot open %s"
+                  % (dev_id, filename))
+            sys.exit(1)
+
 
 def unbind_all(dev_list, force=False):
     """Unbind method, takes a list of device locations"""
+
+    if dev_list[0] == "dpdk":
+        for d in devices.keys():
+            if "Driver_str" in devices[d]:
+                if devices[d]["Driver_str"] in dpdk_drivers:
+                    unbind_one(devices[d]["Slot"], force)
+        return
+
     dev_list = map(dev_id_from_dev_name, dev_list)
     for d in dev_list:
         unbind_one(d, force)
@@ -491,7 +510,7 @@ def bind_all(dev_list, driver, force=False):
     for d in dev_list:
         bind_one(d, driver, force)
 
-    # For kenels < 3.15 when binding devices to a generic driver
+    # For kernels < 3.15 when binding devices to a generic driver
     # (i.e. one that doesn't have a PCI ID table) using new_id, some devices
     # that are not bound to any other driver could be bound even if no one has
     # asked them to. hence, we check the list of drivers again, and see if
@@ -542,7 +561,7 @@ def show_device_status(devices_type, device_name):
 
     # split our list of network devices into the three categories above
     for d in devices.keys():
-        if devices_type in devices[d]["Class"]:
+        if device_type_match(devices[d], devices_type):
             if not has_driver(d):
                 no_drv.append(devices[d])
                 continue
@@ -552,26 +571,37 @@ def show_device_status(devices_type, device_name):
                 kernel_drv.append(devices[d])
 
     # print each category separately, so we can clearly see what's used by DPDK
-    display_devices("%s devices using DPDK-compatible driver" % device_name, dpdk_drv,
-                    "drv=%(Driver_str)s unused=%(Module_str)s")
+    display_devices("%s devices using DPDK-compatible driver" % device_name,
+                    dpdk_drv, "drv=%(Driver_str)s unused=%(Module_str)s")
     display_devices("%s devices using kernel driver" % device_name, kernel_drv,
                     "if=%(Interface)s drv=%(Driver_str)s "
                     "unused=%(Module_str)s %(Active)s")
-    display_devices("Other %s devices" % device_name, no_drv, "unused=%(Module_str)s")
+    display_devices("Other %s devices" % device_name, no_drv,
+                    "unused=%(Module_str)s")
 
 def show_status():
     '''Function called when the script is passed the "--status" option.
     Displays to the user what devices are bound to the igb_uio driver, the
     kernel driver or to no driver'''
 
-    show_device_status(network_devices, "Network")
-    show_device_status(crypto_devices, "Crypto")
+    if status_dev == "net" or status_dev == "all":
+        show_device_status(network_devices, "Network")
+
+    if status_dev == "crypto" or status_dev == "all":
+        show_device_status(crypto_devices, "Crypto")
+
+    if status_dev == "event" or status_dev == "all":
+        show_device_status(eventdev_devices, "Eventdev")
+
+    if status_dev == "mempool" or status_dev == "all":
+        show_device_status(mempool_devices, "Mempool")
 
 def parse_args():
     '''Parses the command-line arguments given by the user and takes the
     appropriate action for each'''
     global b_flag
     global status_flag
+    global status_dev
     global force_flag
     global args
     if len(sys.argv) <= 1:
@@ -580,8 +610,8 @@ def parse_args():
 
     try:
         opts, args = getopt.getopt(sys.argv[1:], "b:us",
-                                   ["help", "usage", "status", "force",
-                                    "bind=", "unbind"])
+                                   ["help", "usage", "status", "status-dev=",
+                                    "force", "bind=", "unbind", ])
     except getopt.GetoptError as error:
         print(str(error))
         print("Run '%s --usage' for further information" % sys.argv[0])
@@ -591,8 +621,12 @@ def parse_args():
         if opt == "--help" or opt == "--usage":
             usage()
             sys.exit(0)
+        if opt == "--status-dev":
+            status_flag = True
+            status_dev = arg
         if opt == "--status" or opt == "-s":
             status_flag = True
+            status_dev = "all"
         if opt == "--force":
             force_flag = True
         if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind":
@@ -630,8 +664,11 @@ def do_arg_actions():
     if status_flag:
         if b_flag is not None:
             clear_data()
-            get_device_details(NETWORK_BASE_CLASS)  # refresh if we have changed anything
-            get_device_details(CRYPTO_BASE_CLASS)  # refresh if we have changed anything
+            # refresh if we have changed anything
+            get_device_details(network_devices)
+            get_device_details(crypto_devices)
+            get_device_details(eventdev_devices)
+            get_device_details(mempool_devices)
         show_status()
 
 
@@ -640,8 +677,10 @@ def main():
     parse_args()
     check_modules()
     clear_data()
-    get_device_details(NETWORK_BASE_CLASS)
-    get_device_details(CRYPTO_BASE_CLASS)
+    get_device_details(network_devices)
+    get_device_details(crypto_devices)
+    get_device_details(eventdev_devices)
+    get_device_details(mempool_devices)
     do_arg_actions()
 
 if __name__ == "__main__":