summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vlib/Makefile.am6
-rw-r--r--vlib/vlib/pci/pci.h176
-rw-r--r--vlib/vlib/pci/pci_config.h727
-rw-r--r--vlib/vlib/unix/pci.c235
-rw-r--r--vlib/vlib/unix/pci.h13
-rw-r--r--vlib/vlib/unix/unix.h14
-rw-r--r--vlib/vlib/unix/util.c165
-rw-r--r--vnet/vnet/devices/dpdk/init.c358
8 files changed, 1284 insertions, 410 deletions
diff --git a/vlib/Makefile.am b/vlib/Makefile.am
index b38c843fc5f..17b23dfd1a8 100644
--- a/vlib/Makefile.am
+++ b/vlib/Makefile.am
@@ -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
index 00000000000..737e28ea52a
--- /dev/null
+++ b/vlib/vlib/pci/pci.h
@@ -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
index 00000000000..38215d82e95
--- /dev/null
+++ b/vlib/vlib/pci/pci_config.h
@@ -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 */
diff --git a/vlib/vlib/unix/pci.c b/vlib/vlib/unix/pci.c
index 02c37f72707..75241f3f1c6 100644
--- a/vlib/vlib/unix/pci.c
+++ b/vlib/vlib/unix/pci.c
@@ -46,87 +46,105 @@
#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. */
diff --git a/vlib/vlib/unix/pci.h b/vlib/vlib/unix/pci.h
index b384250eb47..dcbf1cfbf60 100644
--- a/vlib/vlib/unix/pci.h
+++ b/vlib/vlib/unix/pci.h
@@ -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 */
diff --git a/vlib/vlib/unix/unix.h b/vlib/vlib/unix/unix.h
index e3e6aa14176..44a8853e356 100644
--- a/vlib/vlib/unix/unix.h
+++ b/vlib/vlib/unix/unix.h
@@ -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
index 00000000000..d64036024bf
--- /dev/null
+++ b/vlib/vlib/unix/util.c
@@ -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;
+}
+
diff --git a/vnet/vnet/devices/dpdk/init.c b/vnet/vnet/devices/dpdk/init.c
index 179386970cc..716377c198f 100644
--- a/vnet/vnet/devices/dpdk/init.c
+++ b/vnet/vnet/devices/dpdk/init.c
@@ -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);