Rework of DPDK PCI device uio driver binding process 80/780/6
authorDamjan Marion <damarion@cisco.com>
Wed, 13 Apr 2016 16:03:20 +0000 (18:03 +0200)
committerGerrit Code Review <gerrit@fd.io>
Thu, 14 Apr 2016 23:29:13 +0000 (23:29 +0000)
This is complete rework of DPDK PCI initialization. It drops
previous scheme where lspci/route/awk/sed are used and instead
sysfs is solely used for discovering Ethernet PCI devices. Criteria
for blacklisting device is changed from exsiting routing table entry
to simple interface state obtained by SIOCGIFFLAGS ioctl().
It checks for IFF_UP flag, so as long as interface is declared
up and even when carrier is down interface will be blacklisted.

Change-Id: I59961ddcf1c19c728934e7fe746f343983741bf1
Signed-off-by: Damjan Marion <damarion@cisco.com>
vlib/Makefile.am
vlib/vlib/pci/pci.h [new file with mode: 0644]
vlib/vlib/pci/pci_config.h [new file with mode: 0644]
vlib/vlib/unix/pci.c
vlib/vlib/unix/pci.h
vlib/vlib/unix/unix.h
vlib/vlib/unix/util.c [new file with mode: 0644]
vnet/vnet/devices/dpdk/init.c

index b38c843..17b23df 100644 (file)
@@ -65,6 +65,8 @@ nobase_include_HEADERS =                      \
   vlib/node_funcs.h                            \
   vlib/node.h                                  \
   vlib/physmem.h                               \
+  vlib/pci/pci.h                               \
+  vlib/pci/pci_config.h                                \
   vlib/threads.h                               \
   vlib/trace_funcs.h                           \
   vlib/trace.h                                 \
@@ -81,12 +83,14 @@ libvlib_unix_la_SOURCES =                   \
   vlib/unix/plugin.c                           \
   vlib/unix/plugin.h                           \
   vlib/unix/physmem.c                          \
-  vlib/unix/unix.h                              
+  vlib/unix/pci.c                              \
+  vlib/unix/util.c
 
 nobase_include_HEADERS +=                      \
   vlib/unix/cj.h                               \
   vlib/unix/mc_socket.h                                \
   vlib/unix/physmem.h                          \
+  vlib/unix/pci.h                              \
   vlib/unix/plugin.h                           \
   vlib/unix/unix.h
     
diff --git a/vlib/vlib/pci/pci.h b/vlib/vlib/pci/pci.h
new file mode 100644 (file)
index 0000000..737e28e
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * pci.h: PCI definitions.
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef included_vlib_pci_h
+#define included_vlib_pci_h
+
+#include <vlib/vlib.h>
+#include <vlib/pci/pci_config.h>
+
+typedef CLIB_PACKED (union {
+  struct {
+    u16 domain;
+    u8 bus;
+    u8 slot:5;
+    u8 function:3;
+   };
+   u32 as_u32;
+}) vlib_pci_addr_t;
+
+typedef struct {
+  /* Operating system handle for this device. */
+  uword os_handle;
+
+  vlib_pci_addr_t bus_address;
+
+  /* First 64 bytes of configuration space. */
+  union {
+    pci_config_type0_regs_t config0;
+    pci_config_type1_regs_t config1;
+    u8 config_data[256];
+  };
+} vlib_pci_device_t;
+
+typedef struct {
+  u16 vendor_id, device_id;
+} pci_device_id_t;
+
+typedef struct _pci_device_registration {
+  /* Driver init function. */
+  clib_error_t * (* init_function) (vlib_main_t * vm, vlib_pci_device_t * dev);
+
+  char const *kernel_driver;
+  u8 kernel_driver_running;
+
+  /* List of registrations */
+  struct _pci_device_registration * next_registration;
+
+  /* Vendor/device ids supported by this driver. */
+  pci_device_id_t supported_devices[];
+} pci_device_registration_t;
+
+#define PCI_REGISTER_DEVICE(x,...)                              \
+    __VA_ARGS__ pci_device_registration_t x;                    \
+static void __vlib_add_pci_device_registration_##x (void)       \
+    __attribute__((__constructor__)) ;                          \
+static void __vlib_add_pci_device_registration_##x (void)       \
+{                                                               \
+    linux_pci_main_t * lpm = vlib_unix_get_main();              \
+    x.next_registration = lpm->pci_device_registrations;        \
+    lpm->pci_device_registrations = &x;                         \
+}                                                               \
+__VA_ARGS__ pci_device_registration_t x 
+
+
+/* Configuration space read/write. */
+clib_error_t *
+os_read_write_pci_config (uword os_handle,
+                         vlib_read_or_write_t read_or_write,
+                         uword address,
+                         void * data,
+                         u32 n_bytes);
+
+#define _(t)                                                           \
+static inline clib_error_t *                                           \
+os_read_pci_config_##t (uword os_handle, uword address, t * data)      \
+{                                                                      \
+  return os_read_write_pci_config (os_handle, VLIB_READ,               \
+                                  address, data, sizeof (data[0]));    \
+}
+
+_ (u32);
+_ (u16);
+_ (u8);
+
+#undef _
+
+#define _(t)                                                           \
+static inline clib_error_t *                                           \
+os_write_pci_config_##t (uword os_handle, uword address, t * data)     \
+{                                                                      \
+  return os_read_write_pci_config (os_handle, VLIB_WRITE,              \
+                                  address, data, sizeof (data[0]));    \
+}
+
+_ (u32);
+_ (u16);
+_ (u8);
+
+#undef _
+
+clib_error_t *
+os_map_pci_resource (uword os_handle, u32 resource, void ** result);
+
+clib_error_t *
+os_map_pci_resource_fixed (uword os_handle, u32 resource, u8 * addr, 
+                           void ** result);
+
+/* Free's device. */
+void os_free_pci_device (uword os_handle);
+
+void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource, u32 reg_offset, u32 reg_value);
+
+format_function_t format_os_pci_handle;
+
+static inline uword
+unformat_vlib_pci_addr (unformat_input_t * input, va_list * args)
+{
+  vlib_pci_addr_t * addr = va_arg (* args, vlib_pci_addr_t *);
+  u32 x[4];
+
+  if (!unformat (input, "%x:%x:%x.%x", &x[0], &x[1], &x[2], &x[3]))
+    return 0;
+
+  addr->domain   = x[0];
+  addr->bus      = x[1];
+  addr->slot     = x[2];
+  addr->function = x[3];
+
+  return 1;
+}
+
+static inline u8 *
+format_vlib_pci_addr (u8 * s, va_list * va)
+{
+  vlib_pci_addr_t * addr = va_arg (* va, vlib_pci_addr_t *);
+  return format (s, "%04x:%02x:%02x.%x", addr->domain, addr->bus,
+                addr->slot, addr->function);
+}
+
+#endif /* included_vlib_pci_h */
diff --git a/vlib/vlib/pci/pci_config.h b/vlib/vlib/pci/pci_config.h
new file mode 100644 (file)
index 0000000..38215d8
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * pci.h: PCI definitions.
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef included_vlib_pci_config_h
+#define included_vlib_pci_config_h
+
+#include <vppinfra/byte_order.h>
+#include <vppinfra/error.h>
+
+typedef enum {
+  PCI_CLASS_NOT_DEFINED = 0x0000,
+  PCI_CLASS_NOT_DEFINED_VGA = 0x0001,
+
+  PCI_CLASS_STORAGE_SCSI = 0x0100,
+  PCI_CLASS_STORAGE_IDE = 0x0101,
+  PCI_CLASS_STORAGE_FLOPPY = 0x0102,
+  PCI_CLASS_STORAGE_IPI = 0x0103,
+  PCI_CLASS_STORAGE_RAID = 0x0104,
+  PCI_CLASS_STORAGE_OTHER = 0x0180,
+  PCI_CLASS_STORAGE = 0x0100,
+
+  PCI_CLASS_NETWORK_ETHERNET = 0x0200,
+  PCI_CLASS_NETWORK_TOKEN_RING = 0x0201,
+  PCI_CLASS_NETWORK_FDDI = 0x0202,
+  PCI_CLASS_NETWORK_ATM = 0x0203,
+  PCI_CLASS_NETWORK_OTHER = 0x0280,
+  PCI_CLASS_NETWORK = 0x0200,
+
+  PCI_CLASS_DISPLAY_VGA = 0x0300,
+  PCI_CLASS_DISPLAY_XGA = 0x0301,
+  PCI_CLASS_DISPLAY_3D = 0x0302,
+  PCI_CLASS_DISPLAY_OTHER = 0x0380,
+  PCI_CLASS_DISPLAY = 0x0300,
+
+  PCI_CLASS_MULTIMEDIA_VIDEO = 0x0400,
+  PCI_CLASS_MULTIMEDIA_AUDIO = 0x0401,
+  PCI_CLASS_MULTIMEDIA_PHONE = 0x0402,
+  PCI_CLASS_MULTIMEDIA_OTHER = 0x0480,
+  PCI_CLASS_MULTIMEDIA = 0x0400,
+
+  PCI_CLASS_MEMORY_RAM = 0x0500,
+  PCI_CLASS_MEMORY_FLASH = 0x0501,
+  PCI_CLASS_MEMORY_OTHER = 0x0580,
+  PCI_CLASS_MEMORY = 0x0500,
+
+  PCI_CLASS_BRIDGE_HOST = 0x0600,
+  PCI_CLASS_BRIDGE_ISA = 0x0601,
+  PCI_CLASS_BRIDGE_EISA = 0x0602,
+  PCI_CLASS_BRIDGE_MC = 0x0603,
+  PCI_CLASS_BRIDGE_PCI = 0x0604,
+  PCI_CLASS_BRIDGE_PCMCIA = 0x0605,
+  PCI_CLASS_BRIDGE_NUBUS = 0x0606,
+  PCI_CLASS_BRIDGE_CARDBUS = 0x0607,
+  PCI_CLASS_BRIDGE_RACEWAY = 0x0608,
+  PCI_CLASS_BRIDGE_OTHER = 0x0680,
+  PCI_CLASS_BRIDGE = 0x0600,
+
+  PCI_CLASS_COMMUNICATION_SERIAL = 0x0700,
+  PCI_CLASS_COMMUNICATION_PARALLEL = 0x0701,
+  PCI_CLASS_COMMUNICATION_MULTISERIAL = 0x0702,
+  PCI_CLASS_COMMUNICATION_MODEM = 0x0703,
+  PCI_CLASS_COMMUNICATION_OTHER = 0x0780,
+  PCI_CLASS_COMMUNICATION = 0x0700,
+
+  PCI_CLASS_SYSTEM_PIC = 0x0800,
+  PCI_CLASS_SYSTEM_DMA = 0x0801,
+  PCI_CLASS_SYSTEM_TIMER = 0x0802,
+  PCI_CLASS_SYSTEM_RTC = 0x0803,
+  PCI_CLASS_SYSTEM_PCI_HOTPLUG = 0x0804,
+  PCI_CLASS_SYSTEM_OTHER = 0x0880,
+  PCI_CLASS_SYSTEM = 0x0800,
+
+  PCI_CLASS_INPUT_KEYBOARD = 0x0900,
+  PCI_CLASS_INPUT_PEN = 0x0901,
+  PCI_CLASS_INPUT_MOUSE = 0x0902,
+  PCI_CLASS_INPUT_SCANNER = 0x0903,
+  PCI_CLASS_INPUT_GAMEPORT = 0x0904,
+  PCI_CLASS_INPUT_OTHER = 0x0980,
+  PCI_CLASS_INPUT = 0x0900,
+
+  PCI_CLASS_DOCKING_GENERIC = 0x0a00,
+  PCI_CLASS_DOCKING_OTHER = 0x0a80,
+  PCI_CLASS_DOCKING = 0x0a00,
+
+  PCI_CLASS_PROCESSOR_386 = 0x0b00,
+  PCI_CLASS_PROCESSOR_486 = 0x0b01,
+  PCI_CLASS_PROCESSOR_PENTIUM = 0x0b02,
+  PCI_CLASS_PROCESSOR_ALPHA = 0x0b10,
+  PCI_CLASS_PROCESSOR_POWERPC = 0x0b20,
+  PCI_CLASS_PROCESSOR_MIPS = 0x0b30,
+  PCI_CLASS_PROCESSOR_CO = 0x0b40,
+  PCI_CLASS_PROCESSOR = 0x0b00,
+
+  PCI_CLASS_SERIAL_FIREWIRE = 0x0c00,
+  PCI_CLASS_SERIAL_ACCESS = 0x0c01,
+  PCI_CLASS_SERIAL_SSA = 0x0c02,
+  PCI_CLASS_SERIAL_USB = 0x0c03,
+  PCI_CLASS_SERIAL_FIBER = 0x0c04,
+  PCI_CLASS_SERIAL_SMBUS = 0x0c05,
+  PCI_CLASS_SERIAL = 0x0c00,
+
+  PCI_CLASS_INTELLIGENT_I2O = 0x0e00,
+  PCI_CLASS_INTELLIGENT = 0x0e00,
+
+  PCI_CLASS_SATELLITE_TV = 0x0f00,
+  PCI_CLASS_SATELLITE_AUDIO = 0x0f01,
+  PCI_CLASS_SATELLITE_VOICE = 0x0f03,
+  PCI_CLASS_SATELLITE_DATA = 0x0f04,
+  PCI_CLASS_SATELLITE = 0x0f00,
+
+  PCI_CLASS_CRYPT_NETWORK = 0x1000,
+  PCI_CLASS_CRYPT_ENTERTAINMENT = 0x1001,
+  PCI_CLASS_CRYPT_OTHER = 0x1080,
+  PCI_CLASS_CRYPT = 0x1000,
+
+  PCI_CLASS_SP_DPIO = 0x1100,
+  PCI_CLASS_SP_OTHER = 0x1180,
+  PCI_CLASS_SP = 0x1100,
+} pci_device_class_t;
+
+static inline pci_device_class_t
+pci_device_class_base (pci_device_class_t c)
+{ return c &~ 0xff; }
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+typedef struct {
+  u16 vendor_id;
+  u16 device_id;
+
+  u16 command;
+#define PCI_COMMAND_IO         (1 << 0) /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY     (1 << 1) /* Enable response in Memory space */
+#define PCI_COMMAND_BUS_MASTER (1 << 2) /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL    (1 << 3) /* Enable response to special cycles */
+#define PCI_COMMAND_WRITE_INVALIDATE (1 << 4) /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE_SNOOP (1 << 5)
+#define PCI_COMMAND_PARITY     (1 << 6)
+#define PCI_COMMAND_WAIT       (1 << 7) /* Enable address/data stepping */
+#define PCI_COMMAND_SERR       (1 << 8) /* Enable SERR */
+#define PCI_COMMAND_BACK_TO_BACK_WRITE (1 << 9)
+#define PCI_COMMAND_INTX_DISABLE (1 << 10) /* INTx Emulation Disable */
+
+  u16 status;
+#define PCI_STATUS_INTX_PENDING (1 << 3)
+#define PCI_STATUS_CAPABILITY_LIST (1 << 4)
+#define PCI_STATUS_66MHZ       (1 << 5) /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF         (1 << 6) /* Support User Definable Features (obsolete) */
+#define PCI_STATUS_BACK_TO_BACK_WRITE (1 << 7) /* Accept fast-back to back */
+#define PCI_STATUS_PARITY_ERROR        (1 << 8) /* Detected parity error */
+#define PCI_STATUS_DEVSEL_GET(x) ((x >> 9) & 3)        /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST (0 << 9)
+#define PCI_STATUS_DEVSEL_MEDIUM (1 << 9)
+#define PCI_STATUS_DEVSEL_SLOW (2 << 9)
+#define PCI_STATUS_SIG_TARGET_ABORT (1 << 11) /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT (1 << 12) /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT (1 << 13) /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR (1 << 14) /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY_ERROR (1 << 15)
+
+  u8 revision_id;
+  u8 programming_interface_class; /* Reg. Level Programming Interface */
+
+  pci_device_class_t device_class : 16;
+
+  u8 cache_size;
+  u8 latency_timer;
+
+  u8 header_type;
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+  u8 bist;
+#define PCI_BIST_CODE_MASK     0x0f    /* Return result */
+#define PCI_BIST_START         0x40    /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE       0x80    /* 1 if BIST capable */
+} pci_config_header_t;
+
+/* Byte swap config header. */
+always_inline void
+pci_config_header_little_to_host (pci_config_header_t * r)
+{
+  if (! CLIB_ARCH_IS_BIG_ENDIAN)
+    return;
+#define _(f,t) r->f = clib_byte_swap_##t (r->f)
+  _ (vendor_id, u16);
+  _ (device_id, u16);
+  _ (command, u16);
+  _ (status, u16);
+  _ (device_class, u16);
+#undef _
+}
+
+/* Header type 0 (normal devices) */
+typedef struct {
+  pci_config_header_t header;
+
+  /*
+   * Base addresses specify locations in memory or I/O space.
+   * Decoded size can be determined by writing a value of 
+   * 0xffffffff to the register, and reading it back. Only 
+   * 1 bits are decoded.
+   */
+  u32 base_address[6];
+
+  u16 cardbus_cis;
+
+  u16 subsystem_vendor_id;
+  u16 subsystem_id;
+
+  u32 rom_address;
+#define PCI_ROM_ADDRESS                0x30    /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK   (~0x7ffUL)
+  u8 first_capability_offset;
+  CLIB_PAD_FROM_TO (0x35, 0x3c);
+
+  u8 interrupt_line;
+  u8 interrupt_pin;
+  u8 min_grant;
+  u8 max_latency;
+
+  u8 capability_data[0];
+} pci_config_type0_regs_t;
+
+always_inline void
+pci_config_type0_little_to_host (pci_config_type0_regs_t * r)
+{
+  int i;
+  if (! CLIB_ARCH_IS_BIG_ENDIAN)
+    return;
+  pci_config_header_little_to_host (&r->header);
+#define _(f,t) r->f = clib_byte_swap_##t (r->f)
+  for (i = 0; i < ARRAY_LEN (r->base_address); i++)
+    _ (base_address[i], u32);
+  _ (cardbus_cis, u16);
+  _ (subsystem_vendor_id, u16);
+  _ (subsystem_id, u16);
+  _ (rom_address, u32);
+#undef _
+}
+
+/* Header type 1 (PCI-to-PCI bridges) */
+typedef struct {
+  pci_config_header_t header;
+
+  u32 base_address[2];
+
+  /* Primary/secondary bus number. */
+  u8 primary_bus;
+  u8 secondary_bus;
+
+  /* Highest bus number behind the bridge */
+  u8 subordinate_bus;
+
+  u8 secondary_bus_latency_timer;
+
+  /* I/O range behind bridge. */
+  u8 io_base, io_limit;
+
+  /* Secondary status register, only bit 14 used */
+  u16 secondary_status;
+
+  /* Memory range behind bridge in units of 64k bytes. */
+  u16 memory_base, memory_limit;
+#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define PCI_MEMORY_RANGE_MASK  (~0x0fUL)
+
+  u16 prefetchable_memory_base, prefetchable_memory_limit;
+#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK    (~0x0fUL)
+
+  u32 prefetchable_memory_base_upper_32bits;
+  u32 prefetchable_memory_limit_upper_32bits;
+  u16 io_base_upper_16bits;
+  u16 io_limit_upper_16bits;
+
+  /* Same as for type 0. */
+  u8 capability_list_offset;
+  CLIB_PAD_FROM_TO (0x35, 0x37);
+
+  u32 rom_address;
+  CLIB_PAD_FROM_TO (0x3c, 0x3e);
+
+  u16 bridge_control;
+#define PCI_BRIDGE_CTL_PARITY  0x01    /* Enable parity detection on secondary interface */
+#define PCI_BRIDGE_CTL_SERR    0x02    /* The same for SERR forwarding */
+#define PCI_BRIDGE_CTL_NO_ISA  0x04    /* Disable bridging of ISA ports */
+#define PCI_BRIDGE_CTL_VGA     0x08    /* Forward VGA addresses */
+#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
+#define PCI_BRIDGE_CTL_BUS_RESET 0x40  /* Secondary bus reset */
+#define PCI_BRIDGE_CTL_FAST_BACK 0x80  /* Fast Back2Back enabled on secondary interface */
+
+  u8 capability_data[0];
+} pci_config_type1_regs_t;
+
+always_inline void
+pci_config_type1_little_to_host (pci_config_type1_regs_t * r)
+{
+  int i;
+  if (! CLIB_ARCH_IS_BIG_ENDIAN)
+    return;
+  pci_config_header_little_to_host (&r->header);
+#define _(f,t) r->f = clib_byte_swap_##t (r->f)
+  for (i = 0; i < ARRAY_LEN (r->base_address); i++)
+    _ (base_address[i], u32);
+  _ (secondary_status, u16);
+  _ (memory_base, u16);
+  _ (memory_limit, u16);
+  _ (prefetchable_memory_base, u16);
+  _ (prefetchable_memory_limit, u16);
+  _ (prefetchable_memory_base_upper_32bits, u32);
+  _ (prefetchable_memory_limit_upper_32bits, u32);
+  _ (io_base_upper_16bits, u16);
+  _ (io_limit_upper_16bits, u16);
+  _ (rom_address, u32);
+  _ (bridge_control, u16);
+#undef _
+}
+
+/* Capabilities. */
+typedef enum pci_capability_type {
+  /* Power Management */
+  PCI_CAP_ID_PM = 1,
+
+  /* Accelerated Graphics Port */
+  PCI_CAP_ID_AGP = 2,
+
+  /* Vital Product Data */
+  PCI_CAP_ID_VPD = 3,
+
+  /* Slot Identification */
+  PCI_CAP_ID_SLOTID = 4,
+
+  /* Message Signalled Interrupts */
+  PCI_CAP_ID_MSI = 5,
+
+  /* CompactPCI HotSwap */
+  PCI_CAP_ID_CHSWP = 6,        
+
+  /* PCI-X */
+  PCI_CAP_ID_PCIX = 7,
+
+  /* Hypertransport. */
+  PCI_CAP_ID_HYPERTRANSPORT = 8,
+
+  /* PCI Standard Hot-Plug Controller */
+  PCI_CAP_ID_SHPC = 0xc,
+
+  /* PCI Express */
+  PCI_CAP_ID_PCIE = 0x10,
+
+  /* MSI-X */
+  PCI_CAP_ID_MSIX = 0x11,
+} pci_capability_type_t;
+
+/* Common header for capabilities. */
+typedef CLIB_PACKED (struct {
+  enum pci_capability_type type : 8;
+
+  u8 next_offset;
+}) pci_capability_regs_t;
+
+always_inline void *
+pci_config_find_capability (pci_config_type0_regs_t * t, int cap_type)
+{
+  pci_capability_regs_t * c;
+  u32 next_offset;
+  u32 ttl = 48;
+
+  if (! (t->header.status & PCI_STATUS_CAPABILITY_LIST))
+    return 0;
+
+  next_offset = t->first_capability_offset;
+  while (ttl-- && next_offset >= 0x40)
+    {
+      c = (void *) t + (next_offset &~ 3);
+      if (c->type == 0xff)
+       break;
+      if (c->type == cap_type)
+       return c;
+      next_offset = c->next_offset;
+    }
+  return 0;
+}
+
+/* Power Management Registers */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+
+  u16 capabilities;
+#define PCI_PM_CAP_VER_MASK    0x0007  /* Version */
+#define PCI_PM_CAP_PME_CLOCK   0x0008  /* PME clock required */
+#define PCI_PM_CAP_RESERVED  0x0010 /* Reserved field */
+#define PCI_PM_CAP_DSI         0x0020  /* Device specific initialization */
+#define PCI_PM_CAP_AUX_POWER   0x01C0  /* Auxilliary power support mask */
+#define PCI_PM_CAP_D1          0x0200  /* D1 power state support */
+#define PCI_PM_CAP_D2          0x0400  /* D2 power state support */
+#define PCI_PM_CAP_PME         0x0800  /* PME pin supported */
+#define PCI_PM_CAP_PME_MASK  0xF800 /* PME Mask of all supported states */
+#define PCI_PM_CAP_PME_D0   0x0800 /* PME# from D0 */
+#define PCI_PM_CAP_PME_D1   0x1000 /* PME# from D1 */
+#define PCI_PM_CAP_PME_D2   0x2000 /* PME# from D2 */
+#define PCI_PM_CAP_PME_D3   0x4000 /* PME# from D3 (hot) */
+#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
+  u16 control;
+#define PCI_PM_CTRL_STATE_MASK 0x0003  /* Current power state (D0 to D3) */
+#define PCI_PM_CTRL_PME_ENABLE 0x0100  /* PME pin enable */
+#define PCI_PM_CTRL_DATA_SEL_MASK      0x1e00  /* Data select (??) */
+#define PCI_PM_CTRL_DATA_SCALE_MASK    0x6000  /* Data scale (??) */
+#define PCI_PM_CTRL_PME_STATUS 0x8000  /* PME pin status */
+
+  u8 extensions;
+#define PCI_PM_PPB_B2_B3       0x40    /* Stop clock when in D3hot (??) */
+#define PCI_PM_BPCC_ENABLE     0x80    /* Bus power/clock control enable (??) */
+
+  u8 data;
+}) pci_power_management_regs_t;
+
+/* AGP registers */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+  u8 version;
+  u8 rest_of_capability_flags;
+
+  u32 status;
+  u32 command;
+  /* Command & status common bits. */
+#define PCI_AGP_RQ_MASK        0xff000000 /* Maximum number of requests - 1 */
+#define PCI_AGP_SBA    0x0200  /* Sideband addressing supported */
+#define PCI_AGP_64BIT  0x0020  /* 64-bit addressing supported */
+#define PCI_AGP_ALLOW_TRANSACTIONS 0x0100      /* Allow processing of AGP transactions */
+#define PCI_AGP_FW     0x0010  /* FW transfers supported/forced */
+#define PCI_AGP_RATE4  0x0004  /* 4x transfer rate supported */
+#define PCI_AGP_RATE2  0x0002  /* 2x transfer rate supported */
+#define PCI_AGP_RATE1  0x0001  /* 1x transfer rate supported */
+}) pci_agp_regs_t;
+
+/* Vital Product Data */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+  u16 address;
+#define PCI_VPD_ADDR_MASK      0x7fff  /* Address mask */
+#define PCI_VPD_ADDR_F         0x8000  /* Write 0, 1 indicates completion */
+
+  u32 data;
+}) pci_vpd_regs_t;
+
+/* Slot Identification */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+  u8 esr;
+#define PCI_SID_ESR_NSLOTS     0x1f    /* Number of expansion slots available */
+#define PCI_SID_ESR_FIC        0x20    /* First In Chassis Flag */
+  u8 chassis;
+}) pci_sid_regs_t;
+
+/* Message Signalled Interrupts registers */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+
+  u16 flags;
+#define PCI_MSI_FLAGS_ENABLE   (1 << 0) /* MSI feature enabled */
+#define PCI_MSI_FLAGS_GET_MAX_QUEUE_SIZE(x) ((x >> 1) & 0x7)
+#define PCI_MSI_FLAGS_MAX_QUEUE_SIZE(x)     (((x) & 0x7) << 1)
+#define PCI_MSI_FLAGS_GET_QUEUE_SIZE(x) ((x >> 4) & 0x7)
+#define PCI_MSI_FLAGS_QUEUE_SIZE(x)     (((x) & 0x7) << 4)
+#define PCI_MSI_FLAGS_64BIT    (1 << 7) /* 64-bit addresses allowed */
+#define PCI_MSI_FLAGS_MASKBIT  (1 << 8) /* 64-bit mask bits allowed */
+
+  u32 address;
+  u32 data;
+  u32 mask_bits;
+}) pci_msi32_regs_t;
+
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+  u16 flags;
+  u32 address[2];
+  u32 data;
+  u32 mask_bits;
+}) pci_msi64_regs_t;
+
+/* CompactPCI Hotswap Register */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+
+  u16 control_status;
+#define PCI_CHSWP_DHA          0x01    /* Device Hiding Arm */
+#define PCI_CHSWP_EIM          0x02    /* ENUM# Signal Mask */
+#define PCI_CHSWP_PIE          0x04    /* Pending Insert or Extract */
+#define PCI_CHSWP_LOO          0x08    /* LED On / Off */
+#define PCI_CHSWP_PI           0x30    /* Programming Interface */
+#define PCI_CHSWP_EXT          0x40    /* ENUM# status - extraction */
+#define PCI_CHSWP_INS          0x80    /* ENUM# status - insertion */
+}) pci_chswp_regs_t;
+
+/* PCIX registers */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+
+  u16 command;
+#define PCIX_CMD_DPERR_E       0x0001  /* Data Parity Error Recovery Enable */
+#define PCIX_CMD_ERO           0x0002  /* Enable Relaxed Ordering */
+#define PCIX_CMD_MAX_READ      0x000c  /* Max Memory Read Byte Count */
+#define PCIX_CMD_MAX_SPLIT     0x0070  /* Max Outstanding Split Transactions */
+#define PCIX_CMD_VERSION(x)    (((x) >> 12) & 3) /* Version */
+
+  u32 status;
+#define PCIX_STATUS_DEVFN      0x000000ff      /* A copy of devfn */
+#define PCIX_STATUS_BUS        0x0000ff00      /* A copy of bus nr */
+#define PCIX_STATUS_64BIT      0x00010000      /* 64-bit device */
+#define PCIX_STATUS_133MHZ     0x00020000      /* 133 MHz capable */
+#define PCIX_STATUS_SPL_DISC   0x00040000      /* Split Completion Discarded */
+#define PCIX_STATUS_UNX_SPL    0x00080000      /* Unexpected Split Completion */
+#define PCIX_STATUS_COMPLEX    0x00100000      /* Device Complexity */
+#define PCIX_STATUS_MAX_READ   0x00600000      /* Designed Max Memory Read Count */
+#define PCIX_STATUS_MAX_SPLIT  0x03800000      /* Designed Max Outstanding Split Transactions */
+#define PCIX_STATUS_MAX_CUM    0x1c000000      /* Designed Max Cumulative Read Size */
+#define PCIX_STATUS_SPL_ERR    0x20000000      /* Rcvd Split Completion Error Msg */
+#define PCIX_STATUS_266MHZ     0x40000000      /* 266 MHz capable */
+#define PCIX_STATUS_533MHZ     0x80000000      /* 533 MHz capable */
+}) pcix_config_regs_t;
+
+static inline int pcie_size_to_code (int bytes)
+{
+  ASSERT (is_pow2 (bytes));
+  ASSERT (bytes <= 4096);
+  return min_log2 (bytes) - 7;
+}
+
+static inline int pcie_code_to_size (int code)
+{
+  int size = 1 << (code + 7);
+  ASSERT (size <= 4096);
+  return size;
+}
+
+/* PCI Express capability registers */
+typedef CLIB_PACKED (struct {
+  pci_capability_regs_t header;
+
+  u16 pcie_capabilities;
+#define PCIE_CAP_VERSION(x)    (((x) >> 0) & 0xf)
+#define PCIE_CAP_DEVICE_TYPE(x)        (((x) >> 4) & 0xf)
+#define PCIE_DEVICE_TYPE_ENDPOINT 0
+#define PCIE_DEVICE_TYPE_LEGACY_ENDPOINT 1
+#define PCIE_DEVICE_TYPE_ROOT_PORT 4
+  /* Upstream/downstream port of PCI Express switch. */
+#define PCIE_DEVICE_TYPE_SWITCH_UPSTREAM 5
+#define PCIE_DEVICE_TYPE_SWITCH_DOWNSTREAM 6
+#define PCIE_DEVICE_TYPE_PCIE_TO_PCI_BRIDGE 7
+#define PCIE_DEVICE_TYPE_PCI_TO_PCIE_BRIDGE 8
+  /* Root complex integrated endpoint. */
+#define PCIE_DEVICE_TYPE_ROOT_COMPLEX_ENDPOINT 9
+#define PCIE_DEVICE_TYPE_ROOT_COMPLEX_EVENT_COLLECTOR 10
+#define PCIE_CAP_SLOW_IMPLEMENTED (1 << 8)
+#define PCIE_CAP_MSI_IRQ(x) (((x) >> 9) & 0x1f)
+
+  u32 dev_capabilities;
+#define PCIE_DEVCAP_MAX_PAYLOAD(x) (128 << (((x) >> 0) & 0x7))
+#define PCIE_DEVCAP_PHANTOM_BITS(x) (((x) >> 3) & 0x3)
+#define PCIE_DEVCAP_EXTENTED_TAG (1 << 5)
+#define PCIE_DEVCAP_L0S        0x1c0   /* L0s Acceptable Latency */
+#define PCIE_DEVCAP_L1 0xe00   /* L1 Acceptable Latency */
+#define PCIE_DEVCAP_ATN_BUT    0x1000  /* Attention Button Present */
+#define PCIE_DEVCAP_ATN_IND    0x2000  /* Attention Indicator Present */
+#define PCIE_DEVCAP_PWR_IND    0x4000  /* Power Indicator Present */
+#define PCIE_DEVCAP_PWR_VAL    0x3fc0000 /* Slot Power Limit Value */
+#define PCIE_DEVCAP_PWR_SCL    0xc000000 /* Slot Power Limit Scale */
+
+  u16 dev_control;
+#define PCIE_CTRL_CERE 0x0001  /* Correctable Error Reporting En. */
+#define PCIE_CTRL_NFERE        0x0002  /* Non-Fatal Error Reporting Enable */
+#define PCIE_CTRL_FERE 0x0004  /* Fatal Error Reporting Enable */
+#define PCIE_CTRL_URRE 0x0008  /* Unsupported Request Reporting En. */
+#define PCIE_CTRL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define PCIE_CTRL_MAX_PAYLOAD(n) (((n) & 7) << 5)
+#define PCIE_CTRL_EXT_TAG      0x0100  /* Extended Tag Field Enable */
+#define PCIE_CTRL_PHANTOM      0x0200  /* Phantom Functions Enable */
+#define PCIE_CTRL_AUX_PME      0x0400  /* Auxiliary Power PM Enable */
+#define PCIE_CTRL_NOSNOOP_EN   0x0800 /* Enable No Snoop */
+#define PCIE_CTRL_MAX_READ_REQUEST(n) (((n) & 7) << 12)
+
+  u16 dev_status;
+#define PCIE_DEVSTA_AUXPD      0x10    /* AUX Power Detected */
+#define PCIE_DEVSTA_TRPND      0x20    /* Transactions Pending */
+
+  u32 link_capabilities;
+  u16 link_control;
+  u16 link_status;
+
+  u32 slot_capabilities;
+  u16 slot_control;
+  u16 slot_status;
+
+  u16 root_control;
+#define PCIE_RTCTL_SECEE       0x01    /* System Error on Correctable Error */
+#define PCIE_RTCTL_SENFEE      0x02    /* System Error on Non-Fatal Error */
+#define PCIE_RTCTL_SEFEE       0x04    /* System Error on Fatal Error */
+#define PCIE_RTCTL_PMEIE       0x08    /* PME Interrupt Enable */
+#define PCIE_RTCTL_CRSSVE      0x10    /* CRS Software Visibility Enable */
+
+  u16 root_capabilities;
+  u32 root_status;
+}) pcie_config_regs_t;
+
+/* PCI express extended capabilities. */
+typedef enum pcie_capability_type {
+  PCIE_CAP_ADVANCED_ERROR = 1,
+  PCIE_CAP_VC = 2,
+  PCIE_CAP_DSN = 3,
+  PCIE_CAP_PWR = 4,
+} pcie_capability_type_t;
+
+/* Common header for capabilities. */
+typedef CLIB_PACKED (struct {
+  enum pcie_capability_type type : 16;
+
+  u16 version : 4;
+
+  u16 next_capability : 12;
+}) pcie_capability_regs_t;
+
+typedef CLIB_PACKED (struct {
+  pcie_capability_regs_t header;
+
+  u32 uncorrectable_status;
+#define PCIE_ERROR_UNC_LINK_TRAINING           (1 << 0)
+#define PCIE_ERROR_UNC_DATA_LINK_PROTOCOL      (1 << 4)
+#define PCIE_ERROR_UNC_SURPRISE_DOWN           (1 << 5)
+#define PCIE_ERROR_UNC_POISONED_TLP            (1 << 12)
+#define PCIE_ERROR_UNC_FLOW_CONTROL            (1 << 13)
+#define PCIE_ERROR_UNC_COMPLETION_TIMEOUT      (1 << 14)
+#define PCIE_ERROR_UNC_COMPLETER_ABORT         (1 << 15)
+#define PCIE_ERROR_UNC_UNEXPECTED_COMPLETION   (1 << 16)
+#define PCIE_ERROR_UNC_RX_OVERFLOW             (1 << 17)
+#define PCIE_ERROR_UNC_MALFORMED_TLP           (1 << 18)
+#define PCIE_ERROR_UNC_CRC_ERROR               (1 << 19)
+#define PCIE_ERROR_UNC_UNSUPPORTED_REQUEST     (1 << 20)
+  u32 uncorrectable_mask;
+  u32 uncorrectable_severity;
+
+  u32 correctable_status;
+#define PCIE_ERROR_COR_RX_ERROR                (1 << 0)
+#define PCIE_ERROR_COR_BAD_TLP         (1 << 6)
+#define PCIE_ERROR_COR_BAD_DLLP                (1 << 7)
+#define PCIE_ERROR_COR_REPLAY_ROLLOVER (1 << 8)
+#define PCIE_ERROR_COR_REPLAY_TIMER    (1 << 12)
+#define PCIE_ERROR_COR_ADVISORY                (1 << 13)
+
+  u32 correctable_mask;
+  u32 control;
+  u32 log[4];
+
+  u32 root_command;
+
+  u32 root_status;
+  u16 correctable_error_source;
+  u16 error_source;
+}) pcie_advanced_error_regs_t;
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1       4
+#define PCI_VC_PORT_REG2       8
+#define PCI_VC_PORT_CTRL       12
+#define PCI_VC_PORT_STATUS     14
+#define PCI_VC_RES_CAP         16
+#define PCI_VC_RES_CTRL                20
+#define PCI_VC_RES_STATUS      26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR            4       /* Data Select Register */
+#define PCI_PWR_DATA           8       /* Data Register */
+#define PCI_PWR_DATA_BASE(x)   ((x) & 0xff)      /* Base Power */
+#define PCI_PWR_DATA_SCALE(x)  (((x) >> 8) & 3)  /* Data Scale */
+#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7)  /* PM Sub State */
+#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define PCI_PWR_DATA_TYPE(x)   (((x) >> 15) & 7)  /* Type */
+#define PCI_PWR_DATA_RAIL(x)   (((x) >> 18) & 7)  /* Power Rail */
+#define PCI_PWR_CAP            12      /* Capability */
+#define PCI_PWR_CAP_BUDGET(x)  ((x) & 1)       /* Included in system budget */
+
+#endif /* included_vlib_pci_config_h */
index 02c37f7..75241f3 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+
 
 linux_pci_main_t linux_pci_main;
 
-static clib_error_t *
-foreach_directory_file (char * dir_name,
-                       clib_error_t * (* f) (void * arg, u8 * path_name, u8 * file_name),
-                       void * arg,
-                       int scan_dirs)
+clib_error_t *
+vlib_pci_bind_to_uio (vlib_pci_device_t * d, char * uio_driver_name)
 {
-  DIR * d;
-  struct dirent * e;
   clib_error_t * error = 0;
-  u8 * s, * t;
+  u8 *s = 0;
+  DIR *dir = 0;
+  struct dirent *e;
+  int fd;
+  pci_config_header_t * c;
+  u8 * dev_dir_name = format(0, "/sys/bus/pci/devices/%U",
+                            format_vlib_pci_addr, &d->bus_address);
+
+  c = &d->config0.header;
+
+  /* if uio sub-directory exists, we are fine, device is
+     already bound to UIO driver */
+  s = format (s, "%v/uio%c", dev_dir_name, 0);
+  if (access ( (char *) s, F_OK) == 0)
+    goto done;
+  vec_reset_length (s);
+
+  /* walk trough all linux interfaces and if interface belonging to
+     this device is founf check if interface is admin up  */
+  dir = opendir ("/sys/class/net");
+  s = format(s, "%U%c", format_vlib_pci_addr, &d->bus_address, 0);
 
-  d = opendir (dir_name);
-  if (! d)
+  if (!dir)
     {
-      /* System has no PCI bus. */
-      if (errno == ENOENT)
-        return 0;
-      return clib_error_return_unix (0, "open `%s'", dir_name);
+      error = clib_error_return (0, "Skipping PCI device %U: failed to "
+                                "read /sys/class/net",
+                                format_vlib_pci_addr, &d->bus_address);
+      goto done;
     }
 
-  s = t = 0;
-  while (1)
+  fd = socket(PF_INET, SOCK_DGRAM, 0);
+
+  while((e = readdir (dir)))
     {
-      e = readdir (d);
-      if (! e)
-       break;
-      if (scan_dirs)
-       {
-         if (e->d_type == DT_DIR
-             && (! strcmp (e->d_name, ".")
-                 || ! strcmp (e->d_name, "..")))
-           continue;
-       }
-      else
-       {
-         if (e->d_type == DT_DIR)
-           continue;
-       }
+      struct ifreq ifr;
+      struct ethtool_drvinfo drvinfo;
 
-      s = format (s, "%s/%s", dir_name, e->d_name);
-      t = format (t, "%s", e->d_name);
-      error = f (arg, s, t);
-      _vec_len (s) = 0;
-      _vec_len (t) = 0;
+      if (e->d_name[0] == '.') /* skip . and .. */
+       continue;
 
-      if (error)
-       break;
-    }
+      memset(&ifr, 0, sizeof ifr);
+      memset(&drvinfo, 0, sizeof drvinfo);
+      ifr.ifr_data = (char *) &drvinfo;
+      strncpy(ifr.ifr_name, e->d_name, IFNAMSIZ);
+      drvinfo.cmd = ETHTOOL_GDRVINFO;
+      ioctl (fd, SIOCETHTOOL, &ifr);
 
-  vec_free (s);
-  closedir (d);
+      if (strcmp ((char *) s, drvinfo.bus_info))
+       continue;
 
-  return error;
-}
+      memset (&ifr, 0, sizeof(ifr));
+      strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ);
+      ioctl (fd, SIOCGIFFLAGS, &ifr);
+      close (fd);
 
-static clib_error_t *
-write_sys_fs (char * file_name, char * fmt, ...)
-{
-  u8 * s;
-  int fd;
+      if (ifr.ifr_flags & IFF_UP)
+       {
+         error = clib_error_return (0, "Skipping PCI device %U as host "
+                                    "interface %s is up",
+                                    format_vlib_pci_addr, &d->bus_address,
+                                    e->d_name);
+         goto done;
+       }
+    }
 
-  fd = open (file_name, O_WRONLY);
-  if (fd < 0)
-    return clib_error_return_unix (0, "open `%s'", file_name);
+  close (fd);
+  vec_reset_length (s);
+
+  s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
+  write_sys_fs ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address);
+  vec_reset_length (s);
 
-  va_list va;
-  va_start (va, fmt);
-  s = va_format (0, fmt, &va);
-  va_end (va);
+  s = format (s, "/sys/bus/pci/drivers/%s/new_id%c", uio_driver_name, 0);
+  write_sys_fs ((char *) s, "0x%04x 0x%04x", c->vendor_id, c->device_id);
+  vec_reset_length (s);
 
-  if (write (fd, s, vec_len (s)) < 0)
-    return clib_error_return_unix (0, "write `%s'", file_name);
+  s = format (s, "/sys/bus/pci/drivers/%s/bind%c", uio_driver_name, 0);
+  write_sys_fs ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address);
 
+done:
+  closedir (dir);
   vec_free (s);
-  close (fd);
-  return 0;
+  vec_free (dev_dir_name);
+  return error;
 }
 
+
 static clib_error_t *
 scan_uio_dir (void * arg, u8 * path_name, u8 * file_name)
 {
@@ -149,7 +167,7 @@ static clib_error_t * linux_pci_uio_read_ready (unix_file_t * uf)
   linux_pci_device_t * l;
   u32 li = uf->private_data;
 
-  l = pool_elt_at_index (pm->pci_devices, li);
+  l = pool_elt_at_index (pm->linux_pci_devices, li);
   vlib_node_set_interrupt_pending (vm, l->device_input_node_index);
 
   /* Let node know which device is interrupting. */
@@ -176,7 +194,7 @@ static uword pci_resource_size (uword os_handle, uword resource)
   struct stat b;
   uword result = 0;
 
-  p = pool_elt_at_index (pm->pci_devices, os_handle);
+  p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
 
   file_name = format (0, "%v/resource%d%c", p->dev_dir_name, resource, 0);
   if (stat ((char *) file_name, &b) >= 0)
@@ -193,7 +211,7 @@ void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource,
   char * file_name;
   clib_error_t * error;
 
-  l = pool_elt_at_index (pm->pci_devices, os_handle);
+  l = pool_elt_at_index (pm->linux_pci_devices, os_handle);
   ASSERT (resource == 0);
   ASSERT (reg_offset < pci_resource_size (os_handle, resource));
   file_name = (char *) format (0, "%s/disable_interrupt_regs%c", l->dev_dir_name, 0);
@@ -203,7 +221,7 @@ void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource,
   vec_free (file_name);
 }
 
-static void add_device (pci_device_t * dev, linux_pci_device_t * pdev)
+static void add_device (vlib_pci_device_t * dev, linux_pci_device_t * pdev)
 {
   linux_pci_main_t * pm = &linux_pci_main;
   linux_pci_device_t * l;
@@ -213,30 +231,12 @@ static void add_device (pci_device_t * dev, linux_pci_device_t * pdev)
 
   c = &dev->config0.header;
 
-  pool_get (pm->pci_devices, l);
+  pool_get (pm->linux_pci_devices, l);
   l[0] = pdev[0];
 
   l->dev_dir_name = vec_dup (l->dev_dir_name);
 
-  /* Parse bus, dev, function from directory name. */
-  {
-    unformat_input_t input;
-
-    unformat_init_string (&input, (char *) l->dev_dir_name,
-                         vec_len (l->dev_dir_name));
-
-    if (! unformat (&input, "/sys/bus/pci/devices/%x:%x:%x.%x",
-                   &x[0], &x[1], &x[2], &x[3]))
-      abort ();
-
-    unformat_free (&input);
-
-    l->bus_address.bus = x[1];
-    l->bus_address.slot_function = (x[2] << 3) | x[3];
-    dev->bus_address = l->bus_address;
-  }
-
-  dev->os_handle = l - pm->pci_devices;
+  dev->os_handle = l - pm->linux_pci_devices;
 
   error = write_sys_fs ("/sys/bus/pci/drivers/uio_pci_dma/new_id",
                        "%x %x", c->vendor_id, c->device_id);
@@ -269,7 +269,7 @@ static void add_device (pci_device_t * dev, linux_pci_device_t * pdev)
     template.read_function = linux_pci_uio_read_ready;
     template.file_descriptor = l->uio_fd;
     template.error_function = linux_pci_uio_error_ready;
-    template.private_data = l - pm->pci_devices;
+    template.private_data = l - pm->linux_pci_devices;
 
     /* To be filled in by driver. */
     l->device_input_node_index = ~0;
@@ -305,7 +305,7 @@ os_read_write_pci_config (uword os_handle,
   linux_pci_device_t * p;
   int n;
 
-  p = pool_elt_at_index (pm->pci_devices, os_handle);
+  p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
 
   if (address != lseek (p->config_fd, address, SEEK_SET))
     return clib_error_return_unix (0, "seek offset %d", address);
@@ -338,7 +338,7 @@ os_map_pci_resource_internal (uword os_handle,
   int flags = MAP_SHARED;
 
   error = 0;
-  p = pool_elt_at_index (pm->pci_devices, os_handle);
+  p = pool_elt_at_index (pm->linux_pci_devices, os_handle);
 
   file_name = format (0, "%v/resource%d%c", p->dev_dir_name, resource, 0);
   fd = open ((char *) file_name, O_RDWR);
@@ -404,9 +404,9 @@ void os_free_pci_device (uword os_handle)
   linux_pci_main_t * pm = &linux_pci_main;
   linux_pci_device_t * l;
 
-  l = pool_elt_at_index (pm->pci_devices, os_handle);
+  l = pool_elt_at_index (pm->linux_pci_devices, os_handle);
   linux_pci_device_free (l);
-  pool_put (pm->pci_devices, l);
+  pool_put (pm->linux_pci_devices, l);
 }
 
 u8 * format_os_pci_handle (u8 * s, va_list * va)
@@ -415,10 +415,9 @@ u8 * format_os_pci_handle (u8 * s, va_list * va)
   uword os_pci_handle = va_arg (*va, uword);
   linux_pci_device_t * l;
 
-  l = pool_elt_at_index (pm->pci_devices, os_pci_handle);
+  l = pool_elt_at_index (pm->linux_pci_devices, os_pci_handle);
   return format (s, "%x/%x/%x", l->bus_address.bus,
-                (l->bus_address.slot_function >> 3),
-                (l->bus_address.slot_function & 0x7));
+                l->bus_address.slot, l->bus_address.function);
 }
 
 static inline pci_device_registration_t *
@@ -450,17 +449,17 @@ static inline u8 kernel_driver_installed (pci_device_registration_t *r)
 
 static clib_error_t *
 init_device_from_registered (vlib_main_t * vm,
-                            pci_device_t * dev,
+                            vlib_pci_device_t * dev,
                             linux_pci_device_t * pdev)
 {
-  unix_main_t * um = vlib_unix_get_main();
+  linux_pci_main_t * lpm = &linux_pci_main;
   pci_device_registration_t * r;
   pci_device_id_t * i;
   pci_config_header_t * c;
 
   c = &dev->config0.header;
 
-  r = um->pci_device_registrations;
+  r = lpm->pci_device_registrations;
 
   while (r)
     {
@@ -490,7 +489,7 @@ init_device_from_registered (vlib_main_t * vm,
 
 static clib_error_t *
 init_device (vlib_main_t * vm,
-            pci_device_t * dev,
+            vlib_pci_device_t * dev,
             linux_pci_device_t * pdev)
 {
   return init_device_from_registered (vm, dev, pdev);
@@ -500,10 +499,11 @@ static clib_error_t *
 scan_device (void * arg, u8 * dev_dir_name, u8 * ignored)
 {
   vlib_main_t * vm = arg;
+  linux_pci_main_t * pm = &linux_pci_main;
   int fd;
   u8 * f;
   clib_error_t * error = 0;
-  pci_device_t dev = {0};
+  vlib_pci_device_t * dev;
   linux_pci_device_t pdev = {0};
 
   f = format (0, "%v/config%c", dev_dir_name, 0);
@@ -519,11 +519,14 @@ scan_device (void * arg, u8 * dev_dir_name, u8 * ignored)
       goto done;
     }
 
+  pool_get (pm->pci_devs, dev);
+
   /* You can only read more that 64 bytes of config space as root; so we try to
      read the full space but fall back to just the first 64 bytes. */
-  if (read (fd, &dev.config_data, sizeof (dev.config_data)) != sizeof (dev.config_data)
-      && read (fd, &dev.config0, sizeof (dev.config0)) != sizeof (dev.config0))
+  if (read (fd, &dev->config_data, sizeof (dev->config_data)) != sizeof (dev->config_data)
+      && read (fd, &dev->config0, sizeof (dev->config0)) != sizeof (dev->config0))
     {
+      pool_put (pm->pci_devs, dev);
       error = clib_error_return_unix (0, "read `%s'", f);
       goto done;
     }
@@ -532,23 +535,44 @@ scan_device (void * arg, u8 * dev_dir_name, u8 * ignored)
     static pci_config_header_t all_ones;
     if (all_ones.vendor_id == 0)
       memset (&all_ones, ~0, sizeof (all_ones));
-    
-    if (! memcmp (&dev.config0.header, &all_ones, sizeof (all_ones)))
+
+    if (! memcmp (&dev->config0.header, &all_ones, sizeof (all_ones)))
       {
+        pool_put (pm->pci_devs, dev);
        error = clib_error_return (0, "invalid PCI config for `%s'", f);
        goto done;
       }
   }
 
-  if (dev.config0.header.header_type == 0)
-    pci_config_type0_little_to_host (&dev.config0);
+  if (dev->config0.header.header_type == 0)
+    pci_config_type0_little_to_host (&dev->config0);
   else
-    pci_config_type1_little_to_host (&dev.config1);
+    pci_config_type1_little_to_host (&dev->config1);
+
+  /* Parse bus, dev, function from directory name. */
+  {
+    unformat_input_t input;
+
+    unformat_init_string (&input, (char *) dev_dir_name,
+                         vec_len (dev_dir_name));
+
+    if (! unformat (&input, "/sys/bus/pci/devices/%U",
+                   unformat_vlib_pci_addr, &dev->bus_address))
+      abort ();
+
+    unformat_free (&input);
+
+    pdev.bus_address = dev->bus_address;
+  }
+
 
   pdev.config_fd = fd;
   pdev.dev_dir_name = dev_dir_name;
 
-  error = init_device (vm, &dev, &pdev);
+  hash_set(pm->pci_dev_index_by_pci_addr, dev->bus_address.as_u32,
+          dev - pm->pci_devs);
+
+  error = init_device (vm, dev, &pdev);
 
  done:
   vec_free (f);
@@ -565,6 +589,9 @@ clib_error_t * pci_bus_init (vlib_main_t * vm)
   if ((error = vlib_call_init_function (vm, unix_input_init)))
     return error;
 
+  ASSERT(sizeof(vlib_pci_addr_t) == sizeof(u32));
+  pm->pci_dev_index_by_pci_addr = hash_create (0, sizeof (uword));
+
   error = foreach_directory_file ("/sys/bus/pci/devices", scan_device, vm, /* scan_dirs */ 0);
 
   /* Complain and continue. might not be root, etc. */
index b384250..dcbf1cf 100644 (file)
@@ -53,7 +53,7 @@ typedef struct {
   int config_fd;
 
   /* PCI bus address for this devices parsed from /sys/bus/pci/devices name. */
-  pci_bus_address_t bus_address;
+  vlib_pci_addr_t bus_address;
 
   /* File descriptor for /dev/uio%d */
   int uio_fd;
@@ -74,16 +74,19 @@ typedef struct {
 /* Pool of PCI devices. */
 typedef struct {
   vlib_main_t * vlib_main;
-  linux_pci_device_t * pci_devices;
+  vlib_pci_device_t * pci_devs;
+  linux_pci_device_t * linux_pci_devices;
+  pci_device_registration_t * pci_device_registrations;
+  uword * pci_dev_index_by_pci_addr;
 } linux_pci_main_t;
 
 extern linux_pci_main_t linux_pci_main;
 
 always_inline linux_pci_device_t *
-pci_dev_for_linux (pci_device_t * dev)
+pci_dev_for_linux (vlib_pci_device_t * dev)
 {
   linux_pci_main_t * pm = &linux_pci_main;
-  return pool_elt_at_index (pm->pci_devices, dev->os_handle);
+  return pool_elt_at_index (pm->linux_pci_devices, dev->os_handle);
 }
 
 /* Call to allocate/initialize the pci subsystem.
@@ -91,4 +94,6 @@ pci_dev_for_linux (pci_device_t * dev)
    pci only when it's needed. */
 clib_error_t * pci_bus_init (vlib_main_t * vm);
 
+clib_error_t * vlib_pci_bind_to_uio (vlib_pci_device_t * d, char * uio_driver_name);
+
 #endif /* included_unix_pci_h */
index e3e6aa1..44a8853 100644 (file)
@@ -175,4 +175,18 @@ static inline unix_main_t * vlib_unix_get_main (void)
 /* thread stack array; vec_len = max number of threads */
 u8 **vlib_thread_stacks;
 
+/* utils */
+
+clib_error_t *
+write_sys_fs (char * file_name, char * fmt, ...);
+
+clib_error_t *
+read_sys_fs (char * file_name, char * fmt, ...);
+
+clib_error_t *
+foreach_directory_file (char * dir_name,
+                       clib_error_t * (* f) (void * arg, u8 * path_name,
+                                             u8 * file_name),
+                       void * arg, int scan_dirs);
+
 #endif /* included_unix_unix_h */
diff --git a/vlib/vlib/unix/util.c b/vlib/vlib/unix/util.c
new file mode 100644 (file)
index 0000000..d640360
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * pci.c: Linux user space PCI bus management.
+ *
+ * Copyright (c) 2008 Eliot Dresselhaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+clib_error_t *
+foreach_directory_file (char * dir_name,
+                       clib_error_t * (* f) (void * arg, u8 * path_name, u8 * file_name),
+                       void * arg,
+                       int scan_dirs)
+{
+  DIR * d;
+  struct dirent * e;
+  clib_error_t * error = 0;
+  u8 * s, * t;
+
+  d = opendir (dir_name);
+  if (! d)
+    {
+      /* System has no PCI bus. */
+      if (errno == ENOENT)
+        return 0;
+      return clib_error_return_unix (0, "open `%s'", dir_name);
+    }
+
+  s = t = 0;
+  while (1)
+    {
+      e = readdir (d);
+      if (! e)
+       break;
+      if (scan_dirs)
+       {
+         if (e->d_type == DT_DIR
+             && (! strcmp (e->d_name, ".")
+                 || ! strcmp (e->d_name, "..")))
+           continue;
+       }
+      else
+       {
+         if (e->d_type == DT_DIR)
+           continue;
+       }
+
+      s = format (s, "%s/%s", dir_name, e->d_name);
+      t = format (t, "%s", e->d_name);
+      error = f (arg, s, t);
+      _vec_len (s) = 0;
+      _vec_len (t) = 0;
+
+      if (error)
+       break;
+    }
+
+  vec_free (s);
+  closedir (d);
+
+  return error;
+}
+
+clib_error_t *
+write_sys_fs (char * file_name, char * fmt, ...)
+{
+  u8 * s;
+  int fd;
+
+  fd = open (file_name, O_WRONLY);
+  if (fd < 0)
+    return clib_error_return_unix (0, "open `%s'", file_name);
+
+  va_list va;
+  va_start (va, fmt);
+  s = va_format (0, fmt, &va);
+  va_end (va);
+
+  if (write (fd, s, vec_len (s)) < 0)
+    return clib_error_return_unix (0, "write `%s'", file_name);
+
+  vec_free (s);
+  close (fd);
+  return 0;
+}
+
+clib_error_t *
+read_sys_fs (char * file_name, char * fmt, ...)
+{
+  unformat_input_t input;
+  u8 * s = 0;
+  int fd;
+  ssize_t sz;
+  uword result;
+
+  fd = open (file_name, O_RDONLY);
+  if (fd < 0)
+    return clib_error_return_unix (0, "open `%s'", file_name);
+
+  vec_validate(s, 4095);
+
+  sz = read(fd, s, vec_len (s));
+  if (sz < 0)
+    {
+      close(fd);
+      vec_free(s);
+      return clib_error_return_unix (0, "read `%s'", file_name);
+    }
+
+  _vec_len(s) = sz;
+  unformat_init_vector(&input, s);
+
+  va_list va;
+  va_start (va, fmt);
+  result = va_unformat (&input, fmt, &va);
+  va_end (va);
+
+  vec_free (s);
+  close (fd);
+
+  if (result == 0)
+    return clib_error_return (0, "unformat error");
+
+  return 0;
+}
+
index 1793869..716377c 100644 (file)
@@ -21,6 +21,8 @@
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/devices/dpdk/dpdk.h>
 #include <vlib/unix/physmem.h>
+#include <vlib/pci/pci.h>
+#include <vlib/unix/pci.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -723,196 +725,62 @@ dpdk_lib_init (dpdk_main_t * dm)
   return 0;
 }
 
-static clib_error_t *
-write_sys_fs (char * file_name, char * fmt, ...)
-{
-  u8 * s;
-  int fd;
-
-  fd = open (file_name, O_WRONLY);
-  if (fd < 0)
-    return clib_error_return_unix (0, "open `%s'", file_name);
-
-  va_list va;
-  va_start (va, fmt);
-  s = va_format (0, fmt, &va);
-  va_end (va);
-  vec_add1 (s, 0); // terminate c string
-
-  if (write (fd, s, vec_len (s)) < 0)
-      return clib_error_return_unix (0, "write '%s' to '%s'", s, file_name);
-
-  vec_free (s);
-  close (fd);
-  return 0;
-}
-
-#define VIRTIO_PCI_NAME  "virtio-pci"
-
-static clib_error_t * dpdk_bind_eth_kernel_drivers (vlib_main_t * vm,
-                                                   char * pci_dev_id,
-                                                   char * kernel_driver)
+static void
+dpdk_bind_devices_to_uio (dpdk_main_t * dm)
 {
-  dpdk_main_t * dm = &dpdk_main;
-  unformat_input_t _in;
-  unformat_input_t * in = &_in;
-  clib_error_t * error = 0;
-  u8 * line = 0, * modcmd = 0, * path = 0;
-  u8 * pci_vid = 0, *pci_did = 0, * devname = 0;
-  char *driver_name = kernel_driver;
-  FILE * fp;
-
-  /* 
-   * Bail out now if we're not running as root.
-   * This allows non-privileged use of the packet generator, etc.
-   */
-  if (geteuid() != 0)
-    return 0;
-
-  /*
-   * Get all ethernet pci device numbers for the device type specified.
-   */
-  modcmd = format (0, "lspci -nDd %s | grep 0200 | "
-                  "awk '{ print $1, $3 }'%c", pci_dev_id, 0);
-  if ((fp = popen ((const char *)modcmd, "r")) == NULL)
-    {
-      error = clib_error_return_unix (0, 
-                                     "Unable to get %s ethernet pci devices.",
-                                     pci_dev_id);
-      goto done;
-    }
-
-  vec_validate (line, BUFSIZ);
-  vec_validate (path, BUFSIZ);
-  while (fgets ((char *)line, BUFSIZ, fp) != NULL)
-    {
-      struct stat st;
-      u8 bind_uio = 1;
-      line[strlen ((char *)line) - 1] = 0; // chomp trailing newline.
-
-      unformat_init_string (in, (char *)line, strlen((char *)line) + 1);
-      unformat(in, "%s %s:%s", &devname, &pci_vid, &pci_did);
-      unformat_free (in);
-
-      /*
-       * Blacklist all ethernet interfaces in the 
-       * linux IP routing tables (route --inet --inet6)
-       */
-      if (strstr ((char *)dm->eth_if_blacklist, (char *)devname))
-       continue;
-
-      /*
-       * If there are any devices whitelisted, then blacklist all devices
-       * which are not explicitly whitelisted.
-       */
-      if (dm->eth_if_whitelist && 
-         !strstr ((char *)dm->eth_if_whitelist, (char *)devname))
-       continue;
-
-#ifdef NETMAP
-      /*
-       * Optimistically open the device as a netmap device.
-       */
-      if (eth_nm_open((char *)devname))
+  linux_pci_main_t * pm = &linux_pci_main;
+  clib_error_t * error;
+  vlib_pci_device_t * d;
+  pci_config_header_t * c;
+  u8 * pci_addr = 0;
+
+  pool_foreach (d, pm->pci_devs, ({
+    c = &d->config0.header;
+    vec_reset_length (pci_addr);
+    pci_addr = format (pci_addr, "%U%c", format_vlib_pci_addr, &d->bus_address, 0);
+
+    if (c->device_class != PCI_CLASS_NETWORK_ETHERNET)
+      continue;
+
+    /* if whitelist exists process only whitelisted devices */
+    if (dm->eth_if_whitelist &&
+        !strstr ((char *) dm->eth_if_whitelist, (char *) pci_addr))
+    continue;
+
+    /* virtio */
+    if (c->vendor_id == 0x1af4 && c->device_id == 0x1000)
+      ;
+    /* vmxnet3 */
+    else if (c->vendor_id == 0x15ad && c->device_id == 0x07b0)
+      ;
+    /* all Intel devices */
+    else if (c->vendor_id == 0x8086)
+      ;
+    /* Cisco VIC */
+    else if (c->vendor_id == 0x1137 && c->device_id == 0x0043)
+      ;
+    /* Chelsio T4/T5 */
+    else if (c->vendor_id == 0x1425 && (c->device_id & 0xe000) == 0x4000)
+      ;
+    else
+      {
+        clib_warning ("Unsupported Ethernet PCI device 0x%04x:0x%04x found "
+                     "at PCI address %s\n", (u16) c->vendor_id, (u16) c->device_id,
+                     pci_addr);
         continue;
-#endif
-
-      _vec_len (path) = 0;
-      path = format (path, "/sys/bus/pci/devices/%s/driver/unbind%c",
-                    devname, 0);
-
-      /*
-       * If the device is bound to a driver...
-       */
-      if (stat ((const char *)path, &st) == 0)
-       {
-         u8 * device_path;
-
-         /*
-          * If the interface is not a virtio...
-          */
-         if (!driver_name || strcmp(driver_name, VIRTIO_PCI_NAME))
-           {
-              /*
-               * If it is already bound to driver, don't unbind/bind it.
-               */
-              device_path = format (0, "/sys/bus/pci/drivers/%s/%s/device%c",
-                                    driver_name, devname, 0);
-              if (stat ((const char *)device_path, &st) == 0)
-                bind_uio = 0;
-
-              vec_free (device_path);
-           }
-         
-         /*
-          * unbind it from the current driver
-          */
-         if (bind_uio)
-           {
-             _vec_len (path) -= 1;
-             path = format (path, "%c", 0);
-             error = write_sys_fs ((char *)path, "%s", devname);
-             if (error)
-               goto done;
-           }
-       }
-
-      /*
-       * DAW-FIXME: The following bind/unbind dance is necessary for the dpdk
-       *            virtio poll-mode driver to work.  
-       */
-      if (driver_name && !strcmp(driver_name, VIRTIO_PCI_NAME))
-       {
-         /*
-          * bind interface to the native kernel module
-          */
-         _vec_len (path) = 0;
-         path = format (path, "/sys/bus/pci/drivers/%s/bind%c",
-                        driver_name, 0);
-         error = write_sys_fs ((char *)path, "%s", devname);
-         if (error)
-           goto done;
+      }
 
-         /*
-          * unbind interface from the native kernel module
-          */
-         _vec_len (path) -= 5;
-         path = format (path, "unbind%c", 0);
-         error = write_sys_fs ((char *)path, "%s", devname);
-         if (error)
-           goto done;
-       }
+    error = vlib_pci_bind_to_uio (d, (char *) dm->uio_driver_name);
 
-      /*
-       * bind the interface to igb_uio
-       */
-      if (bind_uio)
-       {
-          _vec_len (path) = 0;
-          path = format (path, "/sys/bus/pci/drivers/%s/new_id%c", driver_name, 0);
-          error = write_sys_fs ((char *) path, "%s %s", pci_vid, pci_did);
-
-          _vec_len (path) = 0;
-          path = format (path, "/sys/bus/pci/drivers/%s/bind%c", driver_name, 0);
-         error = write_sys_fs ((char *) path, "%s", devname);
-         if (error)
-            {
-              error = 0;
-              continue;
-            }
-       }
-    }
-  
- done:
-  vec_free (line);
-  vec_free (path);
-  vec_free (devname);
-  vec_free (pci_vid);
-  vec_free (pci_did);
-  vec_free (modcmd);
-  pclose (fp);
-  return error;
+    if (error)
+      {
+       if (!dm->eth_if_whitelist)
+         dm->eth_if_blacklist = format (dm->eth_if_blacklist, "%U ",
+                                        format_vlib_pci_addr, &d->bus_address);
+       clib_error_report (error);
+      }
+  }));
+  vec_free (pci_addr);
 }
 
 static u32
@@ -956,7 +824,6 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
   u8 * s, * tmp = 0;
   u8 * pci_dev_id = 0;
   u8 * rte_cmd = 0, * ethname = 0;
-  FILE * rte_fp;
   u32 log_level;
   int ret, i;
   char * fmt;
@@ -1214,91 +1081,6 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
         }
     }
 
-  /*
-   * Blacklist all ethernet interfaces in the linux IP routing tables.
-   */
-  dm->eth_if_blacklist = format (0, "%c", 0);
-  rte_cmd = format (0, "route --inet --inet6 -n|awk '{print $7}'|sort -u|"
-                    "egrep $(echo $(ls -1d /sys/class/net/*/device|"
-                    "cut -d/ -f5)|sed -s 's/ /|/g')%c", 0);
-  if ((rte_fp = popen ((const char *)rte_cmd, "r")) == NULL)
-    {
-      error = clib_error_return_unix (0, "Unable to find blacklist ethernet"
-                                     " interface(s) in linux routing tables.");
-      goto rte_cmd_err;
-
-    }
-
-  vec_validate (ethname, BUFSIZ);
-  while (fgets ((char *)ethname, BUFSIZ, rte_fp) != NULL)
-    {
-      FILE *rlnk_fp;
-      u8 * rlnk_cmd = 0, * devname = 0;
-
-      ethname[strlen ((char *)ethname) - 1] = 0; // chomp trailing newline.
-
-      rlnk_cmd = format (0, "readlink /sys/class/net/%s%c",
-                        ethname, 0);
-
-      if ((rlnk_fp = popen ((const char *)rlnk_cmd, "r")) == NULL)
-       {
-         error = clib_error_return_unix (0, "Unable to read %s link.",
-                                         ethname);
-         goto rlnk_cmd_err;
-       }
-
-      vec_validate (devname, BUFSIZ);
-      while (fgets ((char *)devname, BUFSIZ, rlnk_fp) != NULL)
-       {
-         char * pci_id = 0;
-         
-         /*
-          * Extract the device PCI ID name from the link. It is the first
-          * PCI ID searching backwards from the end of the link pathname.
-          * For example:
-          *     readlink /sys/class/net/eth0
-          *     ../../devices/pci0000:00/0000:00:0a.0/virtio4/net/eth0
-          */
-         for (pci_id = (char *)((devname + strlen((char *)devname)));
-              ((u8 *)pci_id > devname) && *pci_id != '.'; pci_id--)
-           ;
-
-         /*
-          * Verify that the field found is a valid PCI ID.
-          */
-         if ((*(pci_id - 1) == '.') || ((u8 *)(pci_id - 11) < devname) || 
-             (*(pci_id - 11) != '/') || (*(pci_id - 3) != ':') ||
-             (*(pci_id - 6) != ':'))
-           {
-             devname[strlen ((char *)devname) - 1] = 0; // chomp trailing newline.
-             clib_warning ("Unable to extract %s PCI ID (0x%llx \"%s\") "
-                           "from 0x%llx \"%s\"", ethname, pci_id, pci_id,
-                           devname, devname);
-             continue;
-           }
-
-         pci_id[2] = 0;
-         pci_id -= 10;
-
-          /* Don't blacklist any interfaces which have been whitelisted.
-           */
-          if (dm->eth_if_whitelist &&
-              strstr ((char *)dm->eth_if_whitelist, (char *)pci_id))
-              continue;
-
-         _vec_len (dm->eth_if_blacklist) -= 1; // chomp trailing NULL.
-         dm->eth_if_blacklist = format (dm->eth_if_blacklist, " %s%c",
-                                        pci_id, 0);
-       }
-  
-    rlnk_cmd_err:
-      pclose (rlnk_fp);
-      vec_free (rlnk_cmd);
-      vec_free (devname);
-    }
-
- rte_cmd_err:
-  pclose (rte_fp);
   vec_free (rte_cmd);
   vec_free (ethname);
 
@@ -1336,6 +1118,9 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
       dm->eal_init_args[4] = tmp;
     }
 
+  if (no_pci == 0 && geteuid() == 0)
+    dpdk_bind_devices_to_uio(dm);
+
   /*
    * If there are whitelisted devices,
    * add the whitelist option & device list to the dpdk arg list...
@@ -1365,35 +1150,6 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
       vec_add1 (dm->eal_init_args, pci_dev_id);
     }
 
-  if (no_pci == 0)
-    {
-      /*
-       * Bind Virtio pci devices to the igb_uio kernel driver.
-       */
-      error = dpdk_bind_eth_kernel_drivers (vm, "1af4:1000", VIRTIO_PCI_NAME);
-      if (error)
-        return error;
-
-      /*
-       * Bind vmxnet3 pci devices to the igb_uio kernel driver.
-       */
-      error = dpdk_bind_eth_kernel_drivers (vm, "15ad:07b0",
-                                            (char *) dm->uio_driver_name);
-      if (error)
-        return error;
-
-      /*
-       * Bind Intel ethernet pci devices to igb_uio kernel driver.
-       */
-      error = dpdk_bind_eth_kernel_drivers (vm, "8086:",
-                                            (char *) dm->uio_driver_name);
-      /*
-       * Bind Cisco VIC ethernet pci devices to igb_uio kernel driver.
-       */
-      error = dpdk_bind_eth_kernel_drivers (vm, "1137:0043",
-                                            (char *) dm->uio_driver_name);
-    }
-
   /* set master-lcore */
   tmp = format (0, "--master-lcore%c", 0);
   vec_add1 (dm->eal_init_args, tmp);