diff options
author | Damjan Marion <damarion@cisco.com> | 2016-05-12 22:11:03 +0200 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2016-05-18 13:13:27 +0000 |
commit | 5a206eafdbf9370fead2dd26fcab09e7ff5544c4 (patch) | |
tree | 847c6322c640fafd3a1c40e691bc8b21a7f07009 | |
parent | a2a48305df2dbcf3a930c2cd266754e2519d038e (diff) |
Rework of the old PCI code
* adds support for VPP native PCI drivers using
standard uio_pci_generic kernel driver
* adds generic PCI interrupt callback
* splits code to generic PCI handling and linux specific
* adds new debug cli 'show pci [all]'
Change-Id: I447c2285e319e9725d70688c1b70c9dedda51fdc
Signed-off-by: Damjan Marion <damarion@cisco.com>
-rw-r--r-- | vlib/Makefile.am | 4 | ||||
-rw-r--r-- | vlib/vlib/pci/linux_pci.c (renamed from vlib/vlib/unix/pci.c) | 284 | ||||
-rw-r--r-- | vlib/vlib/pci/pci.c | 166 | ||||
-rw-r--r-- | vlib/vlib/pci/pci.h | 145 | ||||
-rw-r--r-- | vlib/vlib/pci/pci_config.h | 12 | ||||
-rw-r--r-- | vlib/vlib/unix/pci.h | 99 | ||||
-rw-r--r-- | vlib/vlib/unix/physmem.c | 58 | ||||
-rw-r--r-- | vlib/vlib/unix/physmem.h | 3 | ||||
-rw-r--r-- | vlib/vlib/unix/unix.h | 7 | ||||
-rw-r--r-- | vlib/vlib/unix/util.c | 30 | ||||
-rw-r--r-- | vnet/vnet/devices/dpdk/init.c | 7 |
11 files changed, 476 insertions, 339 deletions
diff --git a/vlib/Makefile.am b/vlib/Makefile.am index 17b23dfd1a8..981c2befd5e 100644 --- a/vlib/Makefile.am +++ b/vlib/Makefile.am @@ -37,6 +37,8 @@ libvlib_la_SOURCES = \ vlib/node.c \ vlib/node_cli.c \ vlib/node_format.c \ + vlib/pci/pci.c \ + vlib/pci/linux_pci.c \ vlib/threads.c \ vlib/trace.c @@ -83,14 +85,12 @@ libvlib_unix_la_SOURCES = \ vlib/unix/plugin.c \ vlib/unix/plugin.h \ vlib/unix/physmem.c \ - 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/unix/pci.c b/vlib/vlib/pci/linux_pci.c index b28b542b42e..65b41116789 100644 --- a/vlib/vlib/unix/pci.c +++ b/vlib/vlib/pci/linux_pci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -40,7 +40,6 @@ #include <vlib/vlib.h> #include <vlib/pci/pci.h> #include <vlib/unix/unix.h> -#include <vlib/unix/pci.h> #include <sys/types.h> #include <sys/stat.h> @@ -51,6 +50,48 @@ #include <linux/ethtool.h> #include <linux/sockios.h> +typedef struct { + /* /sys/bus/pci/devices/... directory name for this device. */ + u8 * dev_dir_name; + + /* Resource file descriptors. */ + int * resource_fds; + + /* File descriptor for config space read/write. */ + int config_fd; + + /* File descriptor for /dev/uio%d */ + int uio_fd; + + /* Minor device for uio device. */ + u32 uio_minor; + + /* Index given by unix_file_add. */ + u32 unix_file_index; + +} linux_pci_device_t; + +/* Pool of PCI devices. */ +typedef struct { + vlib_main_t * vlib_main; + linux_pci_device_t * linux_pci_devices; +} linux_pci_main_t; + +extern linux_pci_main_t linux_pci_main; + +always_inline linux_pci_device_t * +pci_dev_for_linux (vlib_pci_device_t * dev) +{ + linux_pci_main_t * pm = &linux_pci_main; + return pool_elt_at_index (pm->linux_pci_devices, dev->os_handle); +} + +/* Call to allocate/initialize the pci subsystem. + This is not an init function so that users can explicitly enable + 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); linux_pci_main_t linux_pci_main; @@ -127,15 +168,15 @@ vlib_pci_bind_to_uio (vlib_pci_device_t * d, char * uio_driver_name) 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); + vlib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address); vec_reset_length (s); 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); + vlib_sysfs_write ((char *) s, "0x%04x 0x%04x", c->vendor_id, c->device_id); vec_reset_length (s); 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); + vlib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, &d->bus_address); done: closedir (dir); @@ -162,19 +203,19 @@ scan_uio_dir (void * arg, u8 * path_name, u8 * file_name) static clib_error_t * linux_pci_uio_read_ready (unix_file_t * uf) { - linux_pci_main_t * pm = &linux_pci_main; - vlib_main_t * vm = pm->vlib_main; - linux_pci_device_t * l; - u32 li = uf->private_data; + vlib_pci_main_t * pm = &pci_main; + vlib_pci_device_t * d; + int __attribute__ ((unused)) rv; - l = pool_elt_at_index (pm->linux_pci_devices, li); - vlib_node_set_interrupt_pending (vm, l->device_input_node_index); + u32 icount; + rv = read(uf->file_descriptor, &icount, 4); - /* Let node know which device is interrupting. */ - { - vlib_node_runtime_t * rt = vlib_node_get_runtime (vm, l->device_input_node_index); - rt->runtime_data[0] |= 1 << l->device_index; - } + d = pool_elt_at_index (pm->pci_devs, uf->private_data); + + if (d->interrupt_handler) + d->interrupt_handler(d); + + vlib_pci_intr_enable(d); return /* no error */ 0; } @@ -186,67 +227,18 @@ static clib_error_t *linux_pci_uio_error_ready (unix_file_t *uf) return clib_error_return (0, "pci device %d: error", error_index); } -static uword pci_resource_size (uword os_handle, uword resource) -{ - linux_pci_main_t * pm = &linux_pci_main; - linux_pci_device_t * p; - u8 * file_name; - struct stat b; - uword result = 0; - - 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) - result = b.st_size; - vec_free (file_name); - return result; -} - -void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource, - u32 reg_offset, u32 reg_value) -{ - linux_pci_main_t * pm = &linux_pci_main; - linux_pci_device_t * l; - char * file_name; - clib_error_t * error; - - 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); - error = write_sys_fs (file_name, "%x %x", reg_offset, reg_value); - if (error) - clib_error_report (error); - vec_free (file_name); -} - static void add_device (vlib_pci_device_t * dev, linux_pci_device_t * pdev) { - linux_pci_main_t * pm = &linux_pci_main; + vlib_pci_main_t * pm = &pci_main; + linux_pci_main_t * lpm = &linux_pci_main; linux_pci_device_t * l; - pci_config_header_t * c; - u32 x[4]; - clib_error_t * error; - - c = &dev->config0.header; - pool_get (pm->linux_pci_devices, l); + pool_get (lpm->linux_pci_devices, l); l[0] = pdev[0]; l->dev_dir_name = vec_dup (l->dev_dir_name); - 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); - if (error) - clib_error_report (error); - error = write_sys_fs ("/sys/bus/pci/drivers/uio_pci_dma/bind", - "%04x:%02x:%02x.%x", x[0], x[1], x[2], x[3]); - /* Errors happen when re-binding so just ignore them. */ - if (error) - clib_error_free (error); + dev->os_handle = l - lpm->linux_pci_devices; { u8 * uio_dir = format (0, "%s/uio", l->dev_dir_name); @@ -269,11 +261,7 @@ static void add_device (vlib_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->linux_pci_devices; - - /* To be filled in by driver. */ - l->device_input_node_index = ~0; - l->device_index = 0; + template.private_data = dev - pm->pci_devs; l->unix_file_index = unix_file_add (um, &template); } @@ -295,25 +283,22 @@ static void linux_pci_device_free (linux_pci_device_t * l) /* 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) +vlib_pci_read_write_config (vlib_pci_device_t * dev, + vlib_read_or_write_t read_or_write, + uword address, + void * data, + u32 n_bytes) { - linux_pci_main_t * pm = &linux_pci_main; + linux_pci_main_t * lpm = &linux_pci_main; linux_pci_device_t * p; int n; - 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); + p = pool_elt_at_index (lpm->linux_pci_devices, dev->os_handle); if (read_or_write == VLIB_READ) - n = read (p->config_fd, data, n_bytes); + n = pread (p->config_fd, data, n_bytes, address); else - n = write (p->config_fd, data, n_bytes); + n = pwrite (p->config_fd, data, n_bytes, address); if (n != n_bytes) return clib_error_return_unix (0, "%s", @@ -382,44 +367,33 @@ os_map_pci_resource_internal (uword os_handle, } clib_error_t * -os_map_pci_resource (uword os_handle, - u32 resource, - void ** result) +vlib_pci_map_resource (vlib_pci_device_t * dev, + u32 resource, + void ** result) { - return (os_map_pci_resource_internal (os_handle, resource, 0 /* addr */, + return (os_map_pci_resource_internal (dev->os_handle, resource, 0 /* addr */, result)); } clib_error_t * -os_map_pci_resource_fixed (uword os_handle, - u32 resource, - u8 *addr, - void ** result) +vlib_pci_map_resource_fixed (vlib_pci_device_t * dev, + u32 resource, + u8 *addr, + void ** result) { - return (os_map_pci_resource_internal (os_handle, resource, addr, result)); + return (os_map_pci_resource_internal (dev->os_handle, resource, addr, result)); } -void os_free_pci_device (uword os_handle) +void vlib_pci_free_device (vlib_pci_device_t * dev) { linux_pci_main_t * pm = &linux_pci_main; linux_pci_device_t * l; - l = pool_elt_at_index (pm->linux_pci_devices, os_handle); + l = pool_elt_at_index (pm->linux_pci_devices, dev->os_handle); linux_pci_device_free (l); pool_put (pm->linux_pci_devices, l); } -u8 * format_os_pci_handle (u8 * s, va_list * va) -{ - linux_pci_main_t * pm = &linux_pci_main; - uword os_pci_handle = va_arg (*va, uword); - linux_pci_device_t * l; - - 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, l->bus_address.function); -} - pci_device_registration_t * __attribute__((unused)) pci_device_next_registered (pci_device_registration_t * r) { @@ -432,52 +406,35 @@ pci_device_next_registered (pci_device_registration_t * r) return clib_elf_section_data_next (r, i * sizeof (r->supported_devices[0])); } -static inline u8 kernel_driver_installed (pci_device_registration_t *r) -{ - u8 * link_name; - struct stat b; - - link_name = format (0, "/sys/bus/pci/drivers/%s", r->kernel_driver); - if (stat ((char *)link_name, &b) >= 0) - r->kernel_driver_running++; - else - r->kernel_driver_running=0; - - vec_free (link_name); - return r->kernel_driver_running; -} - static clib_error_t * init_device_from_registered (vlib_main_t * vm, vlib_pci_device_t * dev, linux_pci_device_t * pdev) { - linux_pci_main_t * lpm = &linux_pci_main; + vlib_pci_main_t * pm = &pci_main; pci_device_registration_t * r; pci_device_id_t * i; pci_config_header_t * c; + clib_error_t * error; c = &dev->config0.header; - r = lpm->pci_device_registrations; + r = pm->pci_device_registrations; while (r) { for (i = r->supported_devices; i->vendor_id != 0; i++) if (i->vendor_id == c->vendor_id && i->device_id == c->device_id) { - if (r->kernel_driver && kernel_driver_installed(r)) - { - if (r->kernel_driver_running == 1) - { - clib_warning("PCI device type [%04x:%04x] is busy!\n" - "\tUninstall the associated linux kernel " - "driver: sudo rmmod %s", - c->vendor_id, c->device_id, r->kernel_driver); - } - continue; - } + error = vlib_pci_bind_to_uio (dev, "uio_pci_generic"); + if (error) + { + clib_error_report (error); + continue; + } + add_device (dev, pdev); + dev->interrupt_handler = r->interrupt_handler; return r->init_function (vm, dev); } r = r->next_registration; @@ -499,7 +456,7 @@ 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; + vlib_pci_main_t * pm = &pci_main; int fd; u8 * f; clib_error_t * error = 0; @@ -562,7 +519,6 @@ scan_device (void * arg, u8 * dev_dir_name, u8 * ignored) unformat_free (&input); - pdev.bus_address = dev->bus_address; } @@ -574,14 +530,60 @@ scan_device (void * arg, u8 * dev_dir_name, u8 * ignored) error = init_device (vm, dev, &pdev); + vec_reset_length(f); + f = format (f, "%v/vpd%c", dev_dir_name, 0); + fd = open ((char *) f, O_RDONLY); + if (fd >= 0) + { + while (1) + { + u8 tag[3]; + u8 * data = 0; + int len; + + if (read (fd, &tag, 3) != 3) + break; + + if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91) + break; + + len = (tag[2] << 8) | tag[1]; + vec_validate(data, len); + + if (read (fd, data, len) != len) + { + vec_free (data); + break; + } + if (tag[0] == 0x82) + dev->product_name = data; + else if (tag[0] == 0x90) + dev->vpd_r = data; + else if (tag[0] == 0x91) + dev->vpd_w = data; + + data = 0; + } + close (fd); + } + + vec_reset_length(f); + f = format (f, "%v/driver%c", dev_dir_name, 0); + dev->driver_name = vlib_sysfs_link_to_name((char *) f); + + dev->numa_node = -1; + vec_reset_length(f); + f = format (f, "%v/numa_node%c", dev_dir_name, 0); + vlib_sysfs_read ((char *) f, "%u", &dev->numa_node); + done: vec_free (f); return error; } -clib_error_t * pci_bus_init (vlib_main_t * vm) +clib_error_t * linux_pci_init (vlib_main_t * vm) { - linux_pci_main_t * pm = &linux_pci_main; + vlib_pci_main_t * pm = &pci_main; clib_error_t * error; pm->vlib_main = vm; @@ -601,4 +603,4 @@ clib_error_t * pci_bus_init (vlib_main_t * vm) return error; } -VLIB_INIT_FUNCTION (pci_bus_init); +VLIB_INIT_FUNCTION (linux_pci_init); diff --git a/vlib/vlib/pci/pci.c b/vlib/vlib/pci/pci.c new file mode 100644 index 00000000000..bbd122153d5 --- /dev/null +++ b/vlib/vlib/pci/pci.c @@ -0,0 +1,166 @@ +/* + * 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/pci/pci.h> +#include <vlib/unix/unix.h> + +#include <sys/types.h> +#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> + +vlib_pci_main_t pci_main; + +static clib_error_t * +show_pci_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vlib_pci_main_t * pm = &pci_main; + vlib_pci_device_t * d; + pci_config_header_t * c; + int show_all = 0; + u8 * s = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "all")) + show_all = 1; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + vlib_cli_output (vm, "%-13s%-7s%-12s%-15s%-20s%-40s", + "Address", "Socket", "VID:PID", "Link Speed", "Driver", "Product Name"); + + pool_foreach (d, pm->pci_devs, ({ + c = &d->config0.header; + + if (c->device_class != PCI_CLASS_NETWORK_ETHERNET && !show_all) + continue; + + vec_reset_length (s); + + if (d->numa_node >= 0) + s = format (s, " %d", d->numa_node); + + vlib_cli_output (vm, "%-13U%-7v%04x:%04x %-15U%-20s%-40v", + format_vlib_pci_addr, &d->bus_address, s, + c->vendor_id, c->device_id, + format_vlib_pci_link_speed, d, + d->driver_name ? (char *) d->driver_name : "", + d->product_name); + })); + + vec_free(s); + return 0; +} + +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; +} + +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); +} + +u8 * +format_vlib_pci_handle (u8 * s, va_list * va) +{ + vlib_pci_addr_t * addr = va_arg (* va, vlib_pci_addr_t *); + return format (s, "%x/%x/%x", addr->bus, addr->slot, addr->function); +} + +u8 * +format_vlib_pci_link_speed (u8 *s, va_list * va) +{ + vlib_pci_device_t * d = va_arg (* va, vlib_pci_device_t *); + pcie_config_regs_t * r = pci_config_find_capability (&d->config0, PCI_CAP_ID_PCIE); + int width; + + if (!r) + return format (s, "unknown"); + + width = (r->link_status >> 4) & 0x3f; + + if ((r->link_status & 0xf) == 1) + return format (s, "2.5 GT/s x%u", width); + if ((r->link_status & 0xf) == 2) + return format (s, "5.0 GT/s x%u", width); + if ((r->link_status & 0xf) == 3) + return format (s, "8.0 GT/s x%u", width); + return format (s, "unknown"); +} + + +VLIB_CLI_COMMAND (show_pci_command, static) = { + .path = "show pci", + .short_help = "show pci [all]", + .function = show_pci_fn, +}; + +clib_error_t * pci_bus_init (vlib_main_t * vm) +{ + return 0; +} + +VLIB_INIT_FUNCTION (pci_bus_init); diff --git a/vlib/vlib/pci/pci.h b/vlib/vlib/pci/pci.h index 737e28ea52a..7e8a9fcc80b 100644 --- a/vlib/vlib/pci/pci.h +++ b/vlib/vlib/pci/pci.h @@ -53,7 +53,7 @@ typedef CLIB_PACKED (union { u32 as_u32; }) vlib_pci_addr_t; -typedef struct { +typedef struct vlib_pci_device { /* Operating system handle for this device. */ uword os_handle; @@ -65,6 +65,24 @@ typedef struct { pci_config_type1_regs_t config1; u8 config_data[256]; }; + + /* Interrupt handler */ + void (* interrupt_handler) (struct vlib_pci_device * dev); + + /* Driver name */ + u8 * driver_name; + + /* Numa Node */ + int numa_node; + + /* Vital Product Data */ + u8 * product_name; + u8 * vpd_r; + u8 * vpd_w; + + /* Private data */ + uword private_data; + } vlib_pci_device_t; typedef struct { @@ -75,8 +93,8 @@ 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; + /* Interrupt handler */ + void (* interrupt_handler) (vlib_pci_device_t * dev); /* List of registrations */ struct _pci_device_registration * next_registration; @@ -85,33 +103,46 @@ typedef struct _pci_device_registration { pci_device_id_t supported_devices[]; } pci_device_registration_t; +/* Pool of PCI devices. */ +typedef struct { + vlib_main_t * vlib_main; + vlib_pci_device_t * pci_devs; + pci_device_registration_t * pci_device_registrations; + uword * pci_dev_index_by_pci_addr; +} vlib_pci_main_t; + +extern vlib_pci_main_t pci_main; + #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; \ + vlib_pci_main_t * pm = &pci_main; \ + x.next_registration = pm->pci_device_registrations; \ + pm->pci_device_registrations = &x; \ } \ -__VA_ARGS__ pci_device_registration_t x +__VA_ARGS__ pci_device_registration_t x +clib_error_t * +vlib_pci_bind_to_uio (vlib_pci_device_t * d, char * uio_driver_name); /* 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); +vlib_pci_read_write_config (vlib_pci_device_t * dev, + 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) \ +vlib_pci_read_config_##t (vlib_pci_device_t * dev, \ + uword address, t * data) \ { \ - return os_read_write_pci_config (os_handle, VLIB_READ, \ - address, data, sizeof (data[0])); \ + return vlib_pci_read_write_config (dev, VLIB_READ,address, data, \ + sizeof (data[0])); \ } _ (u32); @@ -122,9 +153,10 @@ _ (u8); #define _(t) \ static inline clib_error_t * \ -os_write_pci_config_##t (uword os_handle, uword address, t * data) \ +vlib_pci_write_config_##t (vlib_pci_device_t * dev, uword address, \ + t * data) \ { \ - return os_read_write_pci_config (os_handle, VLIB_WRITE, \ + return vlib_pci_read_write_config (dev, VLIB_WRITE, \ address, data, sizeof (data[0])); \ } @@ -134,43 +166,72 @@ _ (u8); #undef _ -clib_error_t * -os_map_pci_resource (uword os_handle, u32 resource, void ** result); +static inline clib_error_t * +vlib_pci_intr_enable(vlib_pci_device_t * dev) +{ + u16 command; + clib_error_t * err; -clib_error_t * -os_map_pci_resource_fixed (uword os_handle, u32 resource, u8 * addr, - void ** result); + err = vlib_pci_read_config_u16(dev, 4, &command); -/* Free's device. */ -void os_free_pci_device (uword os_handle); + if (err) + return err; -void os_add_pci_disable_interrupts_reg (uword os_handle, u32 resource, u32 reg_offset, u32 reg_value); + command &= ~PCI_COMMAND_INTX_DISABLE; -format_function_t format_os_pci_handle; + return vlib_pci_write_config_u16(dev, 4, &command); +} -static inline uword -unformat_vlib_pci_addr (unformat_input_t * input, va_list * args) +static inline clib_error_t * +vlib_pci_intr_disable(vlib_pci_device_t * dev) { - vlib_pci_addr_t * addr = va_arg (* args, vlib_pci_addr_t *); - u32 x[4]; + u16 command; + clib_error_t * err; - if (!unformat (input, "%x:%x:%x.%x", &x[0], &x[1], &x[2], &x[3])) - return 0; + err = vlib_pci_read_config_u16(dev, 4, &command); + + if (err) + return err; - addr->domain = x[0]; - addr->bus = x[1]; - addr->slot = x[2]; - addr->function = x[3]; + command |= PCI_COMMAND_INTX_DISABLE; - return 1; + return vlib_pci_write_config_u16(dev, 4, &command); } -static inline u8 * -format_vlib_pci_addr (u8 * s, va_list * va) +static inline clib_error_t * +vlib_pci_bus_master_enable(vlib_pci_device_t * dev) { - 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); + clib_error_t * err; + u16 command; + + /* Set bus master enable (BME) */ + err = vlib_pci_read_config_u16(dev, 4, &command); + + if (err) + return err; + + if (!(command & PCI_COMMAND_BUS_MASTER)) + return 0; + + command |= PCI_COMMAND_BUS_MASTER; + + return vlib_pci_write_config_u16(dev, 4, &command); } +clib_error_t * +vlib_pci_map_resource (vlib_pci_device_t * dev, u32 resource, void ** result); + +clib_error_t * +vlib_pci_map_resource_fixed (vlib_pci_device_t * dev, u32 resource, u8 * addr, + void ** result); + +/* Free's device. */ +void +vlib_pci_free_device (vlib_pci_device_t * dev); + +unformat_function_t unformat_vlib_pci_addr; +format_function_t format_vlib_pci_addr; +format_function_t format_vlib_pci_handle; +format_function_t format_vlib_pci_link_speed; + #endif /* included_vlib_pci_h */ diff --git a/vlib/vlib/pci/pci_config.h b/vlib/vlib/pci/pci_config.h index 9cada51c3ef..9d6f08a7207 100644 --- a/vlib/vlib/pci/pci_config.h +++ b/vlib/vlib/pci/pci_config.h @@ -646,6 +646,18 @@ typedef CLIB_PACKED (struct { u16 root_capabilities; u32 root_status; + + u32 dev_capabilities2; + u16 dev_control2; + u16 dev_status2; + + u32 link_capabilities2; + u16 link_control2; + u16 link_status2; + + u32 slot_capabilities2; + u16 slot_control2; + u16 slot_status2; }) pcie_config_regs_t; /* PCI express extended capabilities. */ diff --git a/vlib/vlib/unix/pci.h b/vlib/vlib/unix/pci.h deleted file mode 100644 index dcbf1cfbf60..00000000000 --- a/vlib/vlib/unix/pci.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2015 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. - */ -/* - * unix/pci.h: Linux specific pci state - * - * 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_unix_pci_h -#define included_unix_pci_h - -#include <vlib/pci/pci.h> - -typedef struct { - /* /sys/bus/pci/devices/... directory name for this device. */ - u8 * dev_dir_name; - - /* Resource file descriptors. */ - int * resource_fds; - - /* File descriptor for config space read/write. */ - int config_fd; - - /* PCI bus address for this devices parsed from /sys/bus/pci/devices name. */ - vlib_pci_addr_t bus_address; - - /* File descriptor for /dev/uio%d */ - int uio_fd; - - /* Minor device for uio device. */ - u32 uio_minor; - - /* Index given by unix_file_add. */ - u32 unix_file_index; - - /* Input node to handle interrupts for this device. */ - u32 device_input_node_index; - - /* Node runtime will be a bitmap of device indices with pending interrupts. */ - u32 device_index; -} linux_pci_device_t; - -/* Pool of PCI devices. */ -typedef struct { - vlib_main_t * vlib_main; - 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 (vlib_pci_device_t * dev) -{ - linux_pci_main_t * pm = &linux_pci_main; - return pool_elt_at_index (pm->linux_pci_devices, dev->os_handle); -} - -/* Call to allocate/initialize the pci subsystem. - This is not an init function so that users can explicitly enable - 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/physmem.c b/vlib/vlib/unix/physmem.c index 185483d6f14..67c2233929d 100644 --- a/vlib/vlib/unix/physmem.c +++ b/vlib/vlib/unix/physmem.c @@ -206,8 +206,6 @@ clib_error_t * unix_physmem_init (vlib_main_t * vm, int physical_memory_required vlib_physmem_main_t * vpm = &vm->physmem_main; physmem_main_t * pm = &physmem_main; clib_error_t * error = 0; - char * dev_uio_dma_file = "/dev/uio-dma"; - int using_fake_memory = 0; /* Avoid multiple calls. */ if (vm->os_physmem_alloc_aligned) @@ -224,63 +222,37 @@ clib_error_t * unix_physmem_init (vlib_main_t * vm, int physical_memory_required if (vlib_app_physmem_init (vm, pm, physical_memory_required)) return 0; - if (physical_memory_required) + if (!pm->no_hugepages && htlb_init(vm)) { - if (!pm->no_hugepages && htlb_init(vm)) - { - fformat(stderr, "%s: use huge pages\n", __FUNCTION__); - return 0; - } - pm->uio_dma_fd = open (dev_uio_dma_file, O_RDWR); + fformat(stderr, "%s: use huge pages\n", __FUNCTION__); + return 0; } - else - pm->uio_dma_fd = -1; - if (pm->uio_dma_fd < 0) + pm->mem = mmap (0, pm->mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pm->mem == MAP_FAILED) { - if (physical_memory_required) - { - error = clib_error_return_unix (0, "open `%s'", dev_uio_dma_file); - goto done; - } - - using_fake_memory = 1; - pm->mem = mmap (0, pm->mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (pm->mem == MAP_FAILED) - { - error = clib_error_return_unix (0, "mmap"); - goto done; - } - - pm->heap = mheap_alloc (pm->mem, pm->mem_size); - - /* Identity map with a single page. */ - vpm->log2_n_bytes_per_page = min_log2 (pm->mem_size); - vec_add1 (vpm->page_table, pointer_to_uword (pm->mem)); + error = clib_error_return_unix (0, "mmap"); + goto done; } - else - error = clib_error_return (0, "uio_dma deprecated"); + + pm->heap = mheap_alloc (pm->mem, pm->mem_size); + + /* Identity map with a single page. */ + vpm->log2_n_bytes_per_page = min_log2 (pm->mem_size); + vec_add1 (vpm->page_table, pointer_to_uword (pm->mem)); vpm->page_mask = pow2_mask (vpm->log2_n_bytes_per_page); vpm->virtual.start = pointer_to_uword (pm->mem); vpm->virtual.size = pm->mem_size; vpm->virtual.end = vpm->virtual.start + vpm->virtual.size; - if (using_fake_memory) - fformat(stderr, "%s: use fake dma pages\n", __FUNCTION__); - else - fformat(stderr, "%s: use uio dma pages\n", __FUNCTION__); + fformat(stderr, "%s: use fake dma pages\n", __FUNCTION__); done: if (error) { if (pm->mem != MAP_FAILED) munmap (pm->mem, pm->mem_size); - if (pm->uio_dma_fd >= 0) - { - close (pm->uio_dma_fd); - pm->uio_dma_fd = -1; - } } return error; } @@ -296,7 +268,7 @@ show_physmem (vlib_main_t * vm, physmem_main_t * pm = &physmem_main; if (pm->heap) - vlib_cli_output (vm, "%U", format_mheap, pm->heap, /* verbose */ 0); + vlib_cli_output (vm, "%U", format_mheap, pm->heap, /* verbose */ 1); else vlib_cli_output (vm, "No physmem allocated."); #endif diff --git a/vlib/vlib/unix/physmem.h b/vlib/vlib/unix/physmem.h index a963be746d8..adbd3478edb 100644 --- a/vlib/vlib/unix/physmem.h +++ b/vlib/vlib/unix/physmem.h @@ -36,9 +36,6 @@ #include <sys/shm.h> typedef struct { - /* File descriptor for /dev/uio-dma. */ - int uio_dma_fd; - /* Virtual memory via mmaped. */ void * mem; diff --git a/vlib/vlib/unix/unix.h b/vlib/vlib/unix/unix.h index 2922b4e2a68..75d5df04e56 100644 --- a/vlib/vlib/unix/unix.h +++ b/vlib/vlib/unix/unix.h @@ -194,10 +194,13 @@ u8 **vlib_thread_stacks; /* utils */ clib_error_t * -write_sys_fs (char * file_name, char * fmt, ...); +vlib_sysfs_write (char * file_name, char * fmt, ...); clib_error_t * -read_sys_fs (char * file_name, char * fmt, ...); +vlib_sysfs_read (char * file_name, char * fmt, ...); + +u8 * +vlib_sysfs_link_to_name(char * link); clib_error_t * foreach_directory_file (char * dir_name, diff --git a/vlib/vlib/unix/util.c b/vlib/vlib/unix/util.c index d64036024bf..7a3a2bf9c47 100644 --- a/vlib/vlib/unix/util.c +++ b/vlib/vlib/unix/util.c @@ -59,7 +59,6 @@ foreach_directory_file (char * dir_name, 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); @@ -101,7 +100,7 @@ foreach_directory_file (char * dir_name, } clib_error_t * -write_sys_fs (char * file_name, char * fmt, ...) +vlib_sysfs_write (char * file_name, char * fmt, ...) { u8 * s; int fd; @@ -124,7 +123,7 @@ write_sys_fs (char * file_name, char * fmt, ...) } clib_error_t * -read_sys_fs (char * file_name, char * fmt, ...) +vlib_sysfs_read (char * file_name, char * fmt, ...) { unformat_input_t input; u8 * s = 0; @@ -163,3 +162,28 @@ read_sys_fs (char * file_name, char * fmt, ...) return 0; } +u8 * +vlib_sysfs_link_to_name(char * link) +{ + char *p, buffer[64]; + unformat_input_t in; + u8 *s = 0; + int r; + + r = readlink(link, buffer, sizeof(buffer) - 1); + + if (r < 0) + return 0; + + buffer[r] = 0; + p = strrchr(buffer, '/'); + + if (!p) + return 0; + + unformat_init_string (&in, p+1, strlen (p+1)); + unformat(&in, "%s", &s); + unformat_free (&in); + + return s; +} diff --git a/vnet/vnet/devices/dpdk/init.c b/vnet/vnet/devices/dpdk/init.c index 121b2ce635c..63fa4c07e5f 100644 --- a/vnet/vnet/devices/dpdk/init.c +++ b/vnet/vnet/devices/dpdk/init.c @@ -22,7 +22,6 @@ #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> @@ -744,7 +743,7 @@ dpdk_lib_init (dpdk_main_t * dm) static void dpdk_bind_devices_to_uio (dpdk_main_t * dm) { - linux_pci_main_t * pm = &linux_pci_main; + vlib_pci_main_t * pm = &pci_main; clib_error_t * error; vlib_pci_device_t * d; pci_config_header_t * c; @@ -1050,7 +1049,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) page_size = 1024; pages_avail = 0; s = format (s, path, page_size * 1024, 0); - read_sys_fs ((char *) s, "%u", &pages_avail); + vlib_sysfs_read ((char *) s, "%u", &pages_avail); vec_reset_length (s); if (page_size * pages_avail < mem) @@ -1059,7 +1058,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) page_size = 2; pages_avail = 0; s = format (s, path, page_size * 1024, 0); - read_sys_fs ((char *) s, "%u", &pages_avail); + vlib_sysfs_read ((char *) s, "%u", &pages_avail); vec_reset_length (s); if (page_size * pages_avail < mem) |