bus/pci: fix devargs on probing again
[dpdk.git] / drivers / bus / pci / linux / pci.c
index 5da6728..71b0a30 100644 (file)
@@ -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 <string.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
-#include <rte_eal_memconfig.h>
 #include <rte_malloc.h>
 #include <rte_devargs.h>
 #include <rte_memcpy.h>
 #include <rte_vfio.h>
 
-#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);