X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fbus%2Fpci%2Flinux%2Fpci.c;h=71b0a3053d5775d728a70b5e18264ab37ce74751;hb=fc67ae91ebae7c48fc27a1d24e0843c50c192459;hp=5da6728fb093fc7fd99b3e792c50e1c4435517d1;hpb=f1b7c6b7f5eb51809aaec66a3fa31e600f2dcd12;p=dpdk.git diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c index 5da6728fb0..71b0a3053d 100644 --- a/drivers/bus/pci/linux/pci.c +++ b/drivers/bus/pci/linux/pci.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation */ #include @@ -38,13 +9,11 @@ #include #include #include -#include #include #include #include #include -#include "eal_private.h" #include "eal_filesystem.h" #include "private.h" @@ -62,7 +31,8 @@ extern struct rte_pci_bus rte_pci_bus; static int -pci_get_kernel_driver_by_path(const char *filename, char *dri_name) +pci_get_kernel_driver_by_path(const char *filename, char *dri_name, + size_t len) { int count; char path[PATH_MAX]; @@ -83,7 +53,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) name = strrchr(path, '/'); if (name) { - strncpy(dri_name, name + 1, strlen(name + 1) + 1); + strlcpy(dri_name, name + 1, len); return 0; } @@ -145,24 +115,28 @@ rte_pci_unmap_device(struct rte_pci_device *dev) } } -void * -pci_find_max_end_va(void) +static int +find_max_end_va(const struct rte_memseg_list *msl, void *arg) { - const struct rte_memseg *seg = rte_eal_get_physmem_layout(); - const struct rte_memseg *last = seg; - unsigned i = 0; + size_t sz = msl->len; + void *end_va = RTE_PTR_ADD(msl->base_va, sz); + void **max_va = arg; - for (i = 0; i < RTE_MAX_MEMSEG; i++, seg++) { - if (seg->addr == NULL) - break; + if (*max_va < end_va) + *max_va = end_va; + return 0; +} - if (seg->addr > last->addr) - last = seg; +void * +pci_find_max_end_va(void) +{ + void *va = NULL; - } - return RTE_PTR_ADD(last->addr, last->len); + rte_memseg_list_walk(find_max_end_va, &va); + return va; } + /* parse one line of the "resource" sysfs file (note that the 'line' * string is modified) */ @@ -253,6 +227,7 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr) return -1; memset(dev, 0, sizeof(*dev)); + dev->device.bus = &rte_pci_bus.bus; dev->addr = *addr; /* get vendor id */ @@ -339,7 +314,7 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr) /* parse driver */ snprintf(filename, sizeof(filename), "%s/driver", dirname); - ret = pci_get_kernel_driver_by_path(filename, driver); + ret = pci_get_kernel_driver_by_path(filename, driver, sizeof(driver)); if (ret < 0) { RTE_LOG(ERR, EAL, "Fail to get kernel driver\n"); free(dev); @@ -373,11 +348,41 @@ pci_scan_one(const char *dirname, const struct rte_pci_addr *addr) if (ret < 0) { rte_pci_insert_device(dev2, dev); } else { /* already registered */ - dev2->kdrv = dev->kdrv; - dev2->max_vfs = dev->max_vfs; - pci_name_set(dev2); - memmove(dev2->mem_resource, dev->mem_resource, - sizeof(dev->mem_resource)); + if (!rte_dev_is_probed(&dev2->device)) { + dev2->kdrv = dev->kdrv; + dev2->max_vfs = dev->max_vfs; + pci_name_set(dev2); + memmove(dev2->mem_resource, + dev->mem_resource, + sizeof(dev->mem_resource)); + } else { + /** + * If device is plugged and driver is + * probed already, (This happens when + * we call rte_dev_probe which will + * scan all device on the bus) we don't + * need to do anything here unless... + **/ + if (dev2->kdrv != dev->kdrv || + dev2->max_vfs != dev->max_vfs) + /* + * This should not happens. + * But it is still possible if + * we unbind a device from + * vfio or uio before hotplug + * remove and rebind it with + * a different configure. + * So we just print out the + * error as an alarm. + */ + RTE_LOG(ERR, EAL, "Unexpected device scan at %s!\n", + filename); + else if (dev2->device.devargs != + dev->device.devargs) { + rte_devargs_remove(dev2->device.devargs); + pci_name_set(dev2); + } + } free(dev); } return 0; @@ -496,152 +501,127 @@ error: return -1; } -/* - * Is pci device bound to any kdrv - */ -static inline int -pci_one_device_is_bound(void) +#if defined(RTE_ARCH_X86) +bool +pci_device_iommu_support_va(const struct rte_pci_device *dev) { - struct rte_pci_device *dev = NULL; - int ret = 0; - - FOREACH_DEVICE_ON_PCIBUS(dev) { - if (dev->kdrv == RTE_KDRV_UNKNOWN || - dev->kdrv == RTE_KDRV_NONE) { - continue; - } else { - ret = 1; - break; - } - } - return ret; -} +#define VTD_CAP_MGAW_SHIFT 16 +#define VTD_CAP_MGAW_MASK (0x3fULL << VTD_CAP_MGAW_SHIFT) + const struct rte_pci_addr *addr = &dev->addr; + char filename[PATH_MAX]; + FILE *fp; + uint64_t mgaw, vtd_cap_reg = 0; -/* - * Any one of the device bound to uio - */ -static inline int -pci_one_device_bound_uio(void) -{ - struct rte_pci_device *dev = NULL; - struct rte_devargs *devargs; - int need_check; - - FOREACH_DEVICE_ON_PCIBUS(dev) { - devargs = dev->device.devargs; - - need_check = 0; - switch (rte_pci_bus.bus.conf.scan_mode) { - case RTE_BUS_SCAN_WHITELIST: - if (devargs && devargs->policy == RTE_DEV_WHITELISTED) - need_check = 1; - break; - case RTE_BUS_SCAN_UNDEFINED: - case RTE_BUS_SCAN_BLACKLIST: - if (devargs == NULL || - devargs->policy != RTE_DEV_BLACKLISTED) - need_check = 1; - break; - } + snprintf(filename, sizeof(filename), + "%s/" PCI_PRI_FMT "/iommu/intel-iommu/cap", + rte_pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid, + addr->function); - if (!need_check) - continue; + fp = fopen(filename, "r"); + if (fp == NULL) { + /* We don't have an Intel IOMMU, assume VA supported */ + if (errno == ENOENT) + return true; - if (dev->kdrv == RTE_KDRV_IGB_UIO || - dev->kdrv == RTE_KDRV_UIO_GENERIC) { - return 1; - } + RTE_LOG(ERR, EAL, "%s(): can't open %s: %s\n", + __func__, filename, strerror(errno)); + return false; } - return 0; -} -/* - * Any one of the device has iova as va - */ -static inline int -pci_one_device_has_iova_va(void) -{ - struct rte_pci_device *dev = NULL; - struct rte_pci_driver *drv = NULL; - - FOREACH_DRIVER_ON_PCIBUS(drv) { - if (drv && drv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) { - FOREACH_DEVICE_ON_PCIBUS(dev) { - if (dev->kdrv == RTE_KDRV_VFIO && - rte_pci_match(drv, dev)) - return 1; - } - } + /* We have an Intel IOMMU */ + if (fscanf(fp, "%" PRIx64, &vtd_cap_reg) != 1) { + RTE_LOG(ERR, EAL, "%s(): can't read %s\n", __func__, filename); + fclose(fp); + return false; } - return 0; -} -/* - * Get iommu class of PCI devices on the bus. - */ -enum rte_iova_mode -rte_pci_get_iommu_class(void) + fclose(fp); + + mgaw = ((vtd_cap_reg & VTD_CAP_MGAW_MASK) >> VTD_CAP_MGAW_SHIFT) + 1; + + /* + * Assuming there is no limitation by now. We can not know at this point + * because the memory has not been initialized yet. Setting the dma mask + * will force a check once memory initialization is done. We can not do + * a fallback to IOVA PA now, but if the dma check fails, the error + * message should advice for using '--iova-mode pa' if IOVA VA is the + * current mode. + */ + rte_mem_set_dma_mask(mgaw); + return true; +} +#elif defined(RTE_ARCH_PPC_64) +bool +pci_device_iommu_support_va(__rte_unused const struct rte_pci_device *dev) { - bool is_bound; - bool is_vfio_noiommu_enabled = true; - bool has_iova_va; - bool is_bound_uio; - bool spapr_iommu = -#if defined(RTE_ARCH_PPC_64) - true; + return false; +} #else - false; +bool +pci_device_iommu_support_va(__rte_unused const struct rte_pci_device *dev) +{ + return true; +} #endif - is_bound = pci_one_device_is_bound(); - if (!is_bound) - return RTE_IOVA_DC; +enum rte_iova_mode +pci_device_iova_mode(const struct rte_pci_driver *pdrv, + const struct rte_pci_device *pdev) +{ + enum rte_iova_mode iova_mode = RTE_IOVA_DC; - has_iova_va = pci_one_device_has_iova_va(); - is_bound_uio = pci_one_device_bound_uio(); + switch (pdev->kdrv) { + case RTE_KDRV_VFIO: { #ifdef VFIO_PRESENT - is_vfio_noiommu_enabled = rte_vfio_noiommu_is_enabled() == true ? - true : false; + static int is_vfio_noiommu_enabled = -1; + + if (is_vfio_noiommu_enabled == -1) { + if (rte_vfio_noiommu_is_enabled() == 1) + is_vfio_noiommu_enabled = 1; + else + is_vfio_noiommu_enabled = 0; + } + if (is_vfio_noiommu_enabled != 0) + iova_mode = RTE_IOVA_PA; + else if ((pdrv->drv_flags & RTE_PCI_DRV_NEED_IOVA_AS_VA) != 0) + iova_mode = RTE_IOVA_VA; #endif + break; + } - if (has_iova_va && !is_bound_uio && !is_vfio_noiommu_enabled && - !spapr_iommu) - return RTE_IOVA_VA; + case RTE_KDRV_IGB_UIO: + case RTE_KDRV_UIO_GENERIC: + iova_mode = RTE_IOVA_PA; + break; - if (has_iova_va) { - RTE_LOG(WARNING, EAL, "Some devices want iova as va but pa will be used because.. "); - if (is_vfio_noiommu_enabled) - RTE_LOG(WARNING, EAL, "vfio-noiommu mode configured\n"); - if (is_bound_uio) - RTE_LOG(WARNING, EAL, "few device bound to UIO\n"); - if (spapr_iommu) - RTE_LOG(WARNING, EAL, "sPAPR IOMMU does not support IOVA as VA\n"); + default: + if ((pdrv->drv_flags & RTE_PCI_DRV_NEED_IOVA_AS_VA) != 0) + iova_mode = RTE_IOVA_VA; + break; } - - return RTE_IOVA_PA; + return iova_mode; } /* Read PCI config space. */ int rte_pci_read_config(const struct rte_pci_device *device, void *buf, size_t len, off_t offset) { + char devname[RTE_DEV_NAME_MAX_LEN] = ""; const struct rte_intr_handle *intr_handle = &device->intr_handle; - switch (intr_handle->type) { - case RTE_INTR_HANDLE_UIO: - case RTE_INTR_HANDLE_UIO_INTX: + switch (device->kdrv) { + case RTE_KDRV_IGB_UIO: + case RTE_KDRV_UIO_GENERIC: return pci_uio_read_config(intr_handle, buf, len, offset); - #ifdef VFIO_PRESENT - case RTE_INTR_HANDLE_VFIO_MSIX: - case RTE_INTR_HANDLE_VFIO_MSI: - case RTE_INTR_HANDLE_VFIO_LEGACY: + case RTE_KDRV_VFIO: return pci_vfio_read_config(intr_handle, buf, len, offset); #endif default: + rte_pci_device_name(&device->addr, devname, + RTE_DEV_NAME_MAX_LEN); RTE_LOG(ERR, EAL, - "Unknown handle type of fd %d\n", - intr_handle->fd); + "Unknown driver type for %s\n", devname); return -1; } } @@ -650,23 +630,22 @@ int rte_pci_read_config(const struct rte_pci_device *device, int rte_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset) { + char devname[RTE_DEV_NAME_MAX_LEN] = ""; const struct rte_intr_handle *intr_handle = &device->intr_handle; - switch (intr_handle->type) { - case RTE_INTR_HANDLE_UIO: - case RTE_INTR_HANDLE_UIO_INTX: + switch (device->kdrv) { + case RTE_KDRV_IGB_UIO: + case RTE_KDRV_UIO_GENERIC: return pci_uio_write_config(intr_handle, buf, len, offset); - #ifdef VFIO_PRESENT - case RTE_INTR_HANDLE_VFIO_MSIX: - case RTE_INTR_HANDLE_VFIO_MSI: - case RTE_INTR_HANDLE_VFIO_LEGACY: + case RTE_KDRV_VFIO: return pci_vfio_write_config(intr_handle, buf, len, offset); #endif default: + rte_pci_device_name(&device->addr, devname, + RTE_DEV_NAME_MAX_LEN); RTE_LOG(ERR, EAL, - "Unknown handle type of fd %d\n", - intr_handle->fd); + "Unknown driver type for %s\n", devname); return -1; } } @@ -683,6 +662,12 @@ pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused, int found = 0; size_t linesz; + if (rte_eal_iopl_init() != 0) { + RTE_LOG(ERR, EAL, "%s(): insufficient ioport permissions for PCI device %s\n", + __func__, dev->name); + return -1; + } + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, dev->addr.domain, dev->addr.bus, dev->addr.devid, dev->addr.function); @@ -723,7 +708,6 @@ pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused, if (!found) return -1; - dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; p->base = start; RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);