2012-09-04 12:54:00 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
2014-06-03 23:42:50 +00:00
|
|
|
*
|
2014-02-10 11:46:50 +00:00
|
|
|
* Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
|
2017-05-09 10:35:04 +00:00
|
|
|
* Copyright 2013-2014 6WIND S.A.
|
2012-09-04 12:54:00 +00:00
|
|
|
* All rights reserved.
|
2014-06-03 23:42:50 +00:00
|
|
|
*
|
2013-09-18 10:00:00 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
2012-09-04 12:54:00 +00:00
|
|
|
* are met:
|
2014-06-03 23:42:50 +00:00
|
|
|
*
|
2013-09-18 10:00:00 +00:00
|
|
|
* * Redistributions of source code must retain the above copyright
|
2012-09-04 12:54:00 +00:00
|
|
|
* notice, this list of conditions and the following disclaimer.
|
2013-09-18 10:00:00 +00:00
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
2012-09-04 12:54:00 +00:00
|
|
|
* distribution.
|
2013-09-18 10:00:00 +00:00
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
2012-09-04 12:54:00 +00:00
|
|
|
* from this software without specific prior written permission.
|
2014-06-03 23:42:50 +00:00
|
|
|
*
|
2013-09-18 10:00:00 +00:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
2012-12-19 16:55:37 +00:00
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2012-09-04 12:54:00 +00:00
|
|
|
|
2014-03-01 12:14:34 +00:00
|
|
|
#include <string.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdint.h>
|
2012-12-19 23:00:00 +00:00
|
|
|
#include <stdlib.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/queue.h>
|
2015-07-08 10:34:50 +00:00
|
|
|
#include <sys/mman.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
#include <rte_errno.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
#include <rte_interrupts.h>
|
2012-12-19 23:00:00 +00:00
|
|
|
#include <rte_log.h>
|
2017-04-11 11:07:31 +00:00
|
|
|
#include <rte_bus.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
#include <rte_pci.h>
|
|
|
|
#include <rte_per_lcore.h>
|
|
|
|
#include <rte_memory.h>
|
|
|
|
#include <rte_memzone.h>
|
|
|
|
#include <rte_eal.h>
|
2013-09-18 10:00:00 +00:00
|
|
|
#include <rte_string_fns.h>
|
|
|
|
#include <rte_common.h>
|
2014-03-01 12:14:34 +00:00
|
|
|
#include <rte_devargs.h>
|
2012-09-04 12:54:00 +00:00
|
|
|
|
|
|
|
#include "eal_private.h"
|
|
|
|
|
2017-04-11 11:07:31 +00:00
|
|
|
extern struct rte_pci_bus rte_pci_bus;
|
|
|
|
|
2016-06-13 15:07:44 +00:00
|
|
|
#define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
|
|
|
|
|
|
|
|
const char *pci_get_sysfs_path(void)
|
|
|
|
{
|
|
|
|
const char *path = NULL;
|
|
|
|
|
|
|
|
path = getenv("SYSFS_PCI_DEVICES");
|
|
|
|
if (path == NULL)
|
|
|
|
return SYSFS_PCI_DEVICES;
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2014-03-01 12:14:54 +00:00
|
|
|
static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
|
2012-09-04 12:54:00 +00:00
|
|
|
{
|
2014-03-01 12:14:34 +00:00
|
|
|
struct rte_devargs *devargs;
|
2017-07-07 00:04:30 +00:00
|
|
|
struct rte_pci_addr addr;
|
|
|
|
struct rte_bus *pbus;
|
2014-03-01 12:14:34 +00:00
|
|
|
|
2017-07-07 00:04:30 +00:00
|
|
|
pbus = rte_bus_find_by_name("pci");
|
2014-03-01 12:14:34 +00:00
|
|
|
TAILQ_FOREACH(devargs, &devargs_list, next) {
|
2017-07-07 00:04:30 +00:00
|
|
|
if (devargs->bus != pbus)
|
2014-03-01 12:14:34 +00:00
|
|
|
continue;
|
2017-07-07 00:04:30 +00:00
|
|
|
devargs->bus->parse(devargs->name, &addr);
|
|
|
|
if (!rte_eal_compare_pci_addr(&dev->addr, &addr))
|
2014-03-01 12:14:54 +00:00
|
|
|
return devargs;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
2014-03-01 12:14:54 +00:00
|
|
|
return NULL;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
|
|
|
|
2017-07-15 17:56:39 +00:00
|
|
|
void
|
|
|
|
pci_name_set(struct rte_pci_device *dev)
|
|
|
|
{
|
|
|
|
struct rte_devargs *devargs;
|
|
|
|
|
|
|
|
/* Each device has its internal, canonical name set. */
|
|
|
|
rte_pci_device_name(&dev->addr,
|
|
|
|
dev->name, sizeof(dev->name));
|
|
|
|
devargs = pci_devargs_lookup(dev);
|
|
|
|
dev->device.devargs = devargs;
|
|
|
|
/* In blacklist mode, if the device is not blacklisted, no
|
|
|
|
* rte_devargs exists for it.
|
|
|
|
*/
|
|
|
|
if (devargs != NULL)
|
|
|
|
/* If an rte_devargs exists, the generic rte_device uses the
|
|
|
|
* given name as its namea
|
|
|
|
*/
|
|
|
|
dev->device.name = dev->device.devargs->name;
|
|
|
|
else
|
|
|
|
/* Otherwise, it uses the internal, canonical form. */
|
|
|
|
dev->device.name = dev->name;
|
|
|
|
}
|
|
|
|
|
2015-07-08 10:34:50 +00:00
|
|
|
/* map a particular resource from a file */
|
|
|
|
void *
|
|
|
|
pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
|
|
|
|
int additional_flags)
|
|
|
|
{
|
|
|
|
void *mapaddr;
|
|
|
|
|
|
|
|
/* Map the PCI memory resource of device */
|
|
|
|
mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_SHARED | additional_flags, fd, offset);
|
|
|
|
if (mapaddr == MAP_FAILED) {
|
|
|
|
RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s (%p)\n",
|
|
|
|
__func__, fd, requested_addr,
|
|
|
|
(unsigned long)size, (unsigned long)offset,
|
|
|
|
strerror(errno), mapaddr);
|
|
|
|
} else
|
|
|
|
RTE_LOG(DEBUG, EAL, " PCI memory mapped at %p\n", mapaddr);
|
|
|
|
|
|
|
|
return mapaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unmap a particular resource */
|
|
|
|
void
|
|
|
|
pci_unmap_resource(void *requested_addr, size_t size)
|
|
|
|
{
|
|
|
|
if (requested_addr == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Unmap the PCI memory resource of device */
|
|
|
|
if (munmap(requested_addr, size)) {
|
|
|
|
RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
|
|
|
|
__func__, requested_addr, (unsigned long)size,
|
|
|
|
strerror(errno));
|
|
|
|
} else
|
|
|
|
RTE_LOG(DEBUG, EAL, " PCI memory unmapped at %p\n",
|
|
|
|
requested_addr);
|
|
|
|
}
|
|
|
|
|
2015-07-08 10:34:53 +00:00
|
|
|
/*
|
2017-04-11 11:07:29 +00:00
|
|
|
* Match the PCI Driver and Device using the ID Table
|
|
|
|
*
|
|
|
|
* @param pci_drv
|
|
|
|
* PCI driver from which ID table would be extracted
|
|
|
|
* @param pci_dev
|
|
|
|
* PCI device to match against the driver
|
|
|
|
* @return
|
|
|
|
* 1 for successful match
|
|
|
|
* 0 for unsuccessful match
|
2015-07-08 10:34:53 +00:00
|
|
|
*/
|
|
|
|
static int
|
2017-04-11 11:07:29 +00:00
|
|
|
rte_pci_match(const struct rte_pci_driver *pci_drv,
|
|
|
|
const struct rte_pci_device *pci_dev)
|
2015-07-08 10:34:53 +00:00
|
|
|
{
|
|
|
|
const struct rte_pci_id *id_table;
|
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
for (id_table = pci_drv->id_table; id_table->vendor_id != 0;
|
|
|
|
id_table++) {
|
2015-07-08 10:34:53 +00:00
|
|
|
/* check if device's identifiers match the driver's ones */
|
2017-04-11 11:07:29 +00:00
|
|
|
if (id_table->vendor_id != pci_dev->id.vendor_id &&
|
2015-07-08 10:34:53 +00:00
|
|
|
id_table->vendor_id != PCI_ANY_ID)
|
|
|
|
continue;
|
2017-04-11 11:07:29 +00:00
|
|
|
if (id_table->device_id != pci_dev->id.device_id &&
|
2015-07-08 10:34:53 +00:00
|
|
|
id_table->device_id != PCI_ANY_ID)
|
|
|
|
continue;
|
2017-04-11 11:07:29 +00:00
|
|
|
if (id_table->subsystem_vendor_id !=
|
|
|
|
pci_dev->id.subsystem_vendor_id &&
|
|
|
|
id_table->subsystem_vendor_id != PCI_ANY_ID)
|
2015-07-08 10:34:53 +00:00
|
|
|
continue;
|
2017-04-11 11:07:29 +00:00
|
|
|
if (id_table->subsystem_device_id !=
|
|
|
|
pci_dev->id.subsystem_device_id &&
|
|
|
|
id_table->subsystem_device_id != PCI_ANY_ID)
|
2015-07-08 10:34:53 +00:00
|
|
|
continue;
|
2017-04-11 11:07:29 +00:00
|
|
|
if (id_table->class_id != pci_dev->id.class_id &&
|
2016-05-24 12:50:36 +00:00
|
|
|
id_table->class_id != RTE_CLASS_ANY_ID)
|
|
|
|
continue;
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
return 1;
|
2015-07-08 10:34:53 +00:00
|
|
|
}
|
2017-04-11 11:07:29 +00:00
|
|
|
|
|
|
|
return 0;
|
2015-07-08 10:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-04-11 11:07:29 +00:00
|
|
|
* If vendor/device ID match, call the probe() function of the
|
2015-07-08 10:34:53 +00:00
|
|
|
* driver.
|
|
|
|
*/
|
|
|
|
static int
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_probe_one_driver(struct rte_pci_driver *dr,
|
|
|
|
struct rte_pci_device *dev)
|
2015-07-08 10:34:53 +00:00
|
|
|
{
|
2017-04-11 11:07:29 +00:00
|
|
|
int ret;
|
|
|
|
struct rte_pci_addr *loc;
|
2015-07-08 10:34:53 +00:00
|
|
|
|
|
|
|
if ((dr == NULL) || (dev == NULL))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
loc = &dev->addr;
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
/* The device is not blacklisted; Check if driver supports it */
|
2017-06-27 14:23:34 +00:00
|
|
|
if (!rte_pci_match(dr, dev))
|
2017-04-11 11:07:29 +00:00
|
|
|
/* Match of device and driver failed */
|
|
|
|
return 1;
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
RTE_LOG(INFO, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
|
|
|
|
loc->domain, loc->bus, loc->devid, loc->function,
|
|
|
|
dev->device.numa_node);
|
|
|
|
|
|
|
|
/* no initialization when blacklisted, return without error */
|
|
|
|
if (dev->device.devargs != NULL &&
|
2017-07-15 17:59:27 +00:00
|
|
|
dev->device.devargs->policy ==
|
|
|
|
RTE_DEV_BLACKLISTED) {
|
2017-04-11 11:07:29 +00:00
|
|
|
RTE_LOG(INFO, EAL, " Device is blacklisted, not"
|
|
|
|
" initializing\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-07-21 09:11:19 +00:00
|
|
|
if (dev->device.numa_node < 0) {
|
|
|
|
RTE_LOG(WARNING, EAL, " Invalid NUMA socket, default to 0\n");
|
|
|
|
dev->device.numa_node = 0;
|
|
|
|
}
|
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
RTE_LOG(INFO, EAL, " probe driver: %x:%x %s\n", dev->id.vendor_id,
|
|
|
|
dev->id.device_id, dr->driver.name);
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) {
|
|
|
|
/* map resources for devices that use igb_uio */
|
2017-05-04 14:48:59 +00:00
|
|
|
ret = rte_pci_map_device(dev);
|
2017-04-11 11:07:29 +00:00
|
|
|
if (ret != 0)
|
|
|
|
return ret;
|
|
|
|
}
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
/* reference driver structure */
|
|
|
|
dev->driver = dr;
|
2017-04-26 08:07:24 +00:00
|
|
|
dev->device.driver = &dr->driver;
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
/* call the driver probe() function */
|
|
|
|
ret = dr->probe(dr, dev);
|
|
|
|
if (ret) {
|
2015-07-08 10:34:53 +00:00
|
|
|
dev->driver = NULL;
|
2017-07-15 17:56:40 +00:00
|
|
|
dev->device.driver = NULL;
|
2017-06-09 10:27:45 +00:00
|
|
|
if ((dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) &&
|
|
|
|
/* Don't unmap if device is unsupported and
|
|
|
|
* driver needs mapped resources.
|
|
|
|
*/
|
|
|
|
!(ret > 0 &&
|
|
|
|
(dr->drv_flags & RTE_PCI_DRV_KEEP_MAPPED_RES)))
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_unmap_device(dev);
|
2017-04-11 11:07:29 +00:00
|
|
|
}
|
2015-07-08 10:34:53 +00:00
|
|
|
|
2017-04-11 11:07:29 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If vendor/device ID match, call the remove() function of the
|
|
|
|
* driver.
|
|
|
|
*/
|
|
|
|
static int
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_detach_dev(struct rte_pci_device *dev)
|
2017-04-11 11:07:29 +00:00
|
|
|
{
|
|
|
|
struct rte_pci_addr *loc;
|
2017-04-11 11:07:30 +00:00
|
|
|
struct rte_pci_driver *dr;
|
2017-04-11 11:07:29 +00:00
|
|
|
|
2017-04-11 11:07:30 +00:00
|
|
|
if (dev == NULL)
|
2017-04-11 11:07:29 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-04-11 11:07:30 +00:00
|
|
|
dr = dev->driver;
|
2017-04-11 11:07:29 +00:00
|
|
|
loc = &dev->addr;
|
|
|
|
|
|
|
|
RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
|
|
|
|
loc->domain, loc->bus, loc->devid,
|
|
|
|
loc->function, dev->device.numa_node);
|
|
|
|
|
|
|
|
RTE_LOG(DEBUG, EAL, " remove driver: %x:%x %s\n", dev->id.vendor_id,
|
|
|
|
dev->id.device_id, dr->driver.name);
|
|
|
|
|
|
|
|
if (dr->remove && (dr->remove(dev) < 0))
|
|
|
|
return -1; /* negative value is an error */
|
|
|
|
|
|
|
|
/* clear driver structure */
|
|
|
|
dev->driver = NULL;
|
|
|
|
|
|
|
|
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
|
|
|
|
/* unmap resources for devices that use igb_uio */
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_unmap_device(dev);
|
2017-04-11 11:07:29 +00:00
|
|
|
|
|
|
|
return 0;
|
2015-07-08 10:34:53 +00:00
|
|
|
}
|
|
|
|
|
2012-09-04 12:54:00 +00:00
|
|
|
/*
|
2016-09-20 12:41:15 +00:00
|
|
|
* If vendor/device ID match, call the probe() function of all
|
2014-06-13 14:52:38 +00:00
|
|
|
* registered driver for the given device. Return -1 if initialization
|
|
|
|
* failed, return 1 if no driver is found for this device.
|
2012-09-04 12:54:00 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
pci_probe_all_drivers(struct rte_pci_device *dev)
|
|
|
|
{
|
|
|
|
struct rte_pci_driver *dr = NULL;
|
2015-02-25 19:32:23 +00:00
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (dev == NULL)
|
|
|
|
return -1;
|
2012-09-04 12:54:00 +00:00
|
|
|
|
2016-10-25 21:50:40 +00:00
|
|
|
/* Check if a driver is already loaded */
|
|
|
|
if (dev->driver != NULL)
|
|
|
|
return 0;
|
|
|
|
|
2017-04-11 11:07:32 +00:00
|
|
|
FOREACH_DRIVER_ON_PCIBUS(dr) {
|
2017-05-04 14:48:59 +00:00
|
|
|
rc = rte_pci_probe_one_driver(dr, dev);
|
2013-07-22 22:00:00 +00:00
|
|
|
if (rc < 0)
|
|
|
|
/* negative value is an error */
|
2014-06-13 14:52:38 +00:00
|
|
|
return -1;
|
2013-07-22 22:00:00 +00:00
|
|
|
if (rc > 0)
|
2016-03-08 15:33:38 +00:00
|
|
|
/* positive value means driver doesn't support it */
|
2012-12-19 16:55:37 +00:00
|
|
|
continue;
|
|
|
|
return 0;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
2014-06-13 14:52:38 +00:00
|
|
|
return 1;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
|
|
|
|
2015-02-25 19:32:23 +00:00
|
|
|
/*
|
|
|
|
* Find the pci device specified by pci address, then invoke probe function of
|
2017-07-06 15:28:12 +00:00
|
|
|
* the driver of the device.
|
2015-02-25 19:32:23 +00:00
|
|
|
*/
|
|
|
|
int
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_probe_one(const struct rte_pci_addr *addr)
|
2015-02-25 19:32:23 +00:00
|
|
|
{
|
|
|
|
struct rte_pci_device *dev = NULL;
|
2017-04-11 11:07:32 +00:00
|
|
|
|
2015-02-25 19:32:23 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (addr == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2016-09-20 12:41:23 +00:00
|
|
|
/* update current pci device in global list, kernel bindings might have
|
|
|
|
* changed since last time we looked at it.
|
|
|
|
*/
|
|
|
|
if (pci_update_device(addr) < 0)
|
|
|
|
goto err_return;
|
|
|
|
|
2017-04-11 11:07:32 +00:00
|
|
|
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
2015-02-25 19:32:23 +00:00
|
|
|
if (rte_eal_compare_pci_addr(&dev->addr, addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = pci_probe_all_drivers(dev);
|
2016-08-04 11:50:06 +00:00
|
|
|
if (ret)
|
2015-02-25 19:32:23 +00:00
|
|
|
goto err_return;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err_return:
|
2016-09-20 12:41:23 +00:00
|
|
|
RTE_LOG(WARNING, EAL,
|
|
|
|
"Requested device " PCI_PRI_FMT " cannot be used\n",
|
|
|
|
addr->domain, addr->bus, addr->devid, addr->function);
|
2015-02-25 19:32:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-07-18 18:35:57 +00:00
|
|
|
* Detach device specified by its pci address.
|
2015-02-25 19:32:23 +00:00
|
|
|
*/
|
|
|
|
int
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_detach(const struct rte_pci_addr *addr)
|
2015-02-25 19:32:23 +00:00
|
|
|
{
|
|
|
|
struct rte_pci_device *dev = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (addr == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2017-04-11 11:07:32 +00:00
|
|
|
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
2015-02-25 19:32:23 +00:00
|
|
|
if (rte_eal_compare_pci_addr(&dev->addr, addr))
|
|
|
|
continue;
|
|
|
|
|
2017-05-04 14:48:59 +00:00
|
|
|
ret = rte_pci_detach_dev(dev);
|
2015-02-25 19:32:23 +00:00
|
|
|
if (ret < 0)
|
2017-04-11 11:07:30 +00:00
|
|
|
/* negative value is an error */
|
2015-02-25 19:32:23 +00:00
|
|
|
goto err_return;
|
2017-04-11 11:07:30 +00:00
|
|
|
if (ret > 0)
|
|
|
|
/* positive value means driver doesn't support it */
|
|
|
|
continue;
|
2015-02-25 19:32:23 +00:00
|
|
|
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_remove_device(dev);
|
2016-09-29 01:41:10 +00:00
|
|
|
free(dev);
|
2015-02-25 19:32:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err_return:
|
|
|
|
RTE_LOG(WARNING, EAL, "Requested device " PCI_PRI_FMT
|
|
|
|
" cannot be used\n", dev->addr.domain, dev->addr.bus,
|
|
|
|
dev->addr.devid, dev->addr.function);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-09-04 12:54:00 +00:00
|
|
|
/*
|
2016-09-20 12:41:15 +00:00
|
|
|
* Scan the content of the PCI bus, and call the probe() function for
|
2012-09-04 12:54:00 +00:00
|
|
|
* all registered drivers that have a matching entry in its id_table
|
|
|
|
* for discovered devices.
|
|
|
|
*/
|
|
|
|
int
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_probe(void)
|
2012-09-04 12:54:00 +00:00
|
|
|
{
|
|
|
|
struct rte_pci_device *dev = NULL;
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
size_t probed = 0, failed = 0;
|
2014-03-01 12:14:54 +00:00
|
|
|
struct rte_devargs *devargs;
|
2014-03-01 12:14:34 +00:00
|
|
|
int probe_all = 0;
|
2014-06-13 14:52:38 +00:00
|
|
|
int ret = 0;
|
2012-09-04 12:54:00 +00:00
|
|
|
|
2017-07-07 00:04:32 +00:00
|
|
|
if (rte_pci_bus.bus.conf.scan_mode != RTE_BUS_SCAN_WHITELIST)
|
2014-03-01 12:14:34 +00:00
|
|
|
probe_all = 1;
|
|
|
|
|
2017-04-11 11:07:32 +00:00
|
|
|
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
probed++;
|
2014-03-01 12:14:54 +00:00
|
|
|
|
2017-07-15 17:56:39 +00:00
|
|
|
devargs = dev->device.devargs;
|
2014-03-01 12:14:54 +00:00
|
|
|
/* probe all or only whitelisted devices */
|
2014-03-01 12:14:34 +00:00
|
|
|
if (probe_all)
|
2014-06-13 14:52:38 +00:00
|
|
|
ret = pci_probe_all_drivers(dev);
|
2014-03-01 12:14:54 +00:00
|
|
|
else if (devargs != NULL &&
|
2017-07-15 17:59:27 +00:00
|
|
|
devargs->policy == RTE_DEV_WHITELISTED)
|
2014-06-13 14:52:38 +00:00
|
|
|
ret = pci_probe_all_drivers(dev);
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
RTE_LOG(ERR, EAL, "Requested device " PCI_PRI_FMT
|
2014-03-01 12:14:34 +00:00
|
|
|
" cannot be used\n", dev->addr.domain, dev->addr.bus,
|
|
|
|
dev->addr.devid, dev->addr.function);
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
rte_errno = errno;
|
|
|
|
failed++;
|
2017-04-04 14:59:20 +00:00
|
|
|
ret = 0;
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
}
|
2014-03-01 12:14:34 +00:00
|
|
|
}
|
2013-09-18 10:00:00 +00:00
|
|
|
|
eal: do not panic on PCI failures
Some devices may be inaccessible for a variety of reasons, or the
PCI-bus may be unavailable causing the whole thing to fail. Still,
better to continue attempts at probes.
Since PCI isn't neccessarily required, it may be possible to simply log
the error and continue on letting the user check the logs and restart
the application when things have failed.
This will usually be an issue because of permissions. However, it could
also be caused by OOM. In either case, errno will contain the
underlying cause.
For linux, it is safe to re-init the system here, so allow the
application to take corrective action and reinit.
For BSD, this is not the case, for other reasons, including hugepage
allocation has already happened, and needs to be properly uninitialized.
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
2017-03-22 20:19:37 +00:00
|
|
|
return (probed && probed == failed) ? -1 : 0;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dump one device */
|
|
|
|
static int
|
2014-05-02 23:42:56 +00:00
|
|
|
pci_dump_one_device(FILE *f, struct rte_pci_device *dev)
|
2012-09-04 12:54:00 +00:00
|
|
|
{
|
2013-05-30 17:12:39 +00:00
|
|
|
int i;
|
|
|
|
|
2014-05-02 23:42:56 +00:00
|
|
|
fprintf(f, PCI_PRI_FMT, dev->addr.domain, dev->addr.bus,
|
2012-09-04 12:54:00 +00:00
|
|
|
dev->addr.devid, dev->addr.function);
|
2014-05-02 23:42:56 +00:00
|
|
|
fprintf(f, " - vendor:%x device:%x\n", dev->id.vendor_id,
|
2012-09-04 12:54:00 +00:00
|
|
|
dev->id.device_id);
|
2013-05-30 17:12:39 +00:00
|
|
|
|
|
|
|
for (i = 0; i != sizeof(dev->mem_resource) /
|
|
|
|
sizeof(dev->mem_resource[0]); i++) {
|
2014-05-02 23:42:56 +00:00
|
|
|
fprintf(f, " %16.16"PRIx64" %16.16"PRIx64"\n",
|
2014-06-03 23:42:50 +00:00
|
|
|
dev->mem_resource[i].phys_addr,
|
2013-05-30 17:12:39 +00:00
|
|
|
dev->mem_resource[i].len);
|
|
|
|
}
|
2012-09-04 12:54:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* dump devices on the bus */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_dump(FILE *f)
|
2012-09-04 12:54:00 +00:00
|
|
|
{
|
|
|
|
struct rte_pci_device *dev = NULL;
|
|
|
|
|
2017-04-11 11:07:32 +00:00
|
|
|
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
2014-05-02 23:42:56 +00:00
|
|
|
pci_dump_one_device(f, dev);
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-07 00:03:10 +00:00
|
|
|
static int
|
|
|
|
pci_parse(const char *name, void *addr)
|
|
|
|
{
|
|
|
|
struct rte_pci_addr *out = addr;
|
|
|
|
struct rte_pci_addr pci_addr;
|
|
|
|
bool parse;
|
|
|
|
|
|
|
|
parse = (eal_parse_pci_BDF(name, &pci_addr) == 0 ||
|
|
|
|
eal_parse_pci_DomBDF(name, &pci_addr) == 0);
|
|
|
|
if (parse && addr != NULL)
|
|
|
|
*out = pci_addr;
|
|
|
|
return parse == false;
|
|
|
|
}
|
|
|
|
|
2012-09-04 12:54:00 +00:00
|
|
|
/* register a driver */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_register(struct rte_pci_driver *driver)
|
2012-09-04 12:54:00 +00:00
|
|
|
{
|
2017-04-11 11:07:32 +00:00
|
|
|
TAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, driver, next);
|
|
|
|
driver->bus = &rte_pci_bus;
|
2012-09-04 12:54:00 +00:00
|
|
|
}
|
|
|
|
|
2013-06-03 00:00:00 +00:00
|
|
|
/* unregister a driver */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_unregister(struct rte_pci_driver *driver)
|
2013-06-03 00:00:00 +00:00
|
|
|
{
|
2017-04-11 11:07:32 +00:00
|
|
|
TAILQ_REMOVE(&rte_pci_bus.driver_list, driver, next);
|
|
|
|
driver->bus = NULL;
|
2013-06-03 00:00:00 +00:00
|
|
|
}
|
2017-04-11 11:07:31 +00:00
|
|
|
|
|
|
|
/* Add a device to PCI bus */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_add_device(struct rte_pci_device *pci_dev)
|
2017-04-11 11:07:31 +00:00
|
|
|
{
|
|
|
|
TAILQ_INSERT_TAIL(&rte_pci_bus.device_list, pci_dev, next);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert a device into a predefined position in PCI bus */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_insert_device(struct rte_pci_device *exist_pci_dev,
|
|
|
|
struct rte_pci_device *new_pci_dev)
|
2017-04-11 11:07:31 +00:00
|
|
|
{
|
|
|
|
TAILQ_INSERT_BEFORE(exist_pci_dev, new_pci_dev, next);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove a device from PCI bus */
|
|
|
|
void
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_remove_device(struct rte_pci_device *pci_dev)
|
2017-04-11 11:07:31 +00:00
|
|
|
{
|
|
|
|
TAILQ_REMOVE(&rte_pci_bus.device_list, pci_dev, next);
|
|
|
|
}
|
|
|
|
|
2017-06-30 18:19:33 +00:00
|
|
|
static struct rte_device *
|
|
|
|
pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
struct rte_pci_device *dev;
|
|
|
|
|
|
|
|
FOREACH_DEVICE_ON_PCIBUS(dev) {
|
2017-07-06 15:28:10 +00:00
|
|
|
if (start && &dev->device == start) {
|
|
|
|
start = NULL; /* starting point found */
|
2017-06-30 18:19:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (cmp(&dev->device, data) == 0)
|
|
|
|
return &dev->device;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-30 18:19:40 +00:00
|
|
|
static int
|
2017-07-15 17:56:42 +00:00
|
|
|
pci_plug(struct rte_device *dev)
|
2017-06-30 18:19:40 +00:00
|
|
|
{
|
2017-07-15 17:56:41 +00:00
|
|
|
return pci_probe_all_drivers(RTE_DEV_TO_PCI(dev));
|
2017-06-30 18:19:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pci_unplug(struct rte_device *dev)
|
|
|
|
{
|
|
|
|
struct rte_pci_device *pdev;
|
2017-07-15 17:56:41 +00:00
|
|
|
int ret;
|
2017-06-30 18:19:40 +00:00
|
|
|
|
|
|
|
pdev = RTE_DEV_TO_PCI(dev);
|
2017-07-15 17:56:41 +00:00
|
|
|
ret = rte_pci_detach_dev(pdev);
|
|
|
|
rte_pci_remove_device(pdev);
|
|
|
|
free(pdev);
|
|
|
|
return ret;
|
2017-06-30 18:19:40 +00:00
|
|
|
}
|
|
|
|
|
2017-04-11 11:07:31 +00:00
|
|
|
struct rte_pci_bus rte_pci_bus = {
|
|
|
|
.bus = {
|
2017-05-04 14:48:59 +00:00
|
|
|
.scan = rte_pci_scan,
|
|
|
|
.probe = rte_pci_probe,
|
2017-06-30 18:19:33 +00:00
|
|
|
.find_device = pci_find_device,
|
2017-06-30 18:19:40 +00:00
|
|
|
.plug = pci_plug,
|
|
|
|
.unplug = pci_unplug,
|
2017-07-07 00:03:10 +00:00
|
|
|
.parse = pci_parse,
|
2017-04-11 11:07:31 +00:00
|
|
|
},
|
|
|
|
.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
|
|
|
|
.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
|
|
|
|
};
|
|
|
|
|
2017-07-07 00:03:07 +00:00
|
|
|
RTE_REGISTER_BUS(pci, rte_pci_bus.bus);
|