X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fbus%2Ffslmc%2Ffslmc_bus.c;h=beb3dd008fbc6d8747560b60f35a9b1276a5d746;hb=185fe122f4899f48569d0086c9dcacc431ef0967;hp=480857e57c741bb071a98d6a737e973c97921d7a;hpb=6eaf4e7c337551fdbc3d5d22721ada5c2d4b8457;p=dpdk.git diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c index 480857e57c..beb3dd008f 100644 --- a/drivers/bus/fslmc/fslmc_bus.c +++ b/drivers/bus/fslmc/fslmc_bus.c @@ -1,33 +1,7 @@ -/*- - * BSD LICENSE +/* SPDX-License-Identifier: BSD-3-Clause * - * Copyright 2016 NXP. + * Copyright 2016,2018-2019 NXP * - * 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 NXP 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. */ #include @@ -36,21 +10,30 @@ #include #include -#include #include #include #include -#include +#include #include #include +#include "fslmc_logs.h" -#define FSLMC_BUS_LOG(level, fmt, args...) \ - RTE_LOG(level, EAL, fmt "\n", ##args) +#include #define VFIO_IOMMU_GROUP_PATH "/sys/kernel/iommu_groups" +#define FSLMC_BUS_NAME fslmc struct rte_fslmc_bus rte_fslmc_bus; +uint8_t dpaa2_virt_mode; + +uint32_t +rte_fslmc_get_device_count(enum rte_dpaa2_dev_type device_type) +{ + if (device_type >= DPAA2_DEVTYPE_MAX) + return 0; + return rte_fslmc_bus.device_count[device_type]; +} static void cleanup_fslmc_device_list(void) @@ -108,14 +91,45 @@ insert_in_device_list(struct rte_dpaa2_device *newdev) TAILQ_INSERT_TAIL(&rte_fslmc_bus.device_list, newdev, next); } +static struct rte_devargs * +fslmc_devargs_lookup(struct rte_dpaa2_device *dev) +{ + struct rte_devargs *devargs; + char dev_name[32]; + + RTE_EAL_DEVARGS_FOREACH("fslmc", devargs) { + devargs->bus->parse(devargs->name, &dev_name); + if (strcmp(dev_name, dev->device.name) == 0) { + DPAA2_BUS_INFO("**Devargs matched %s", dev_name); + return devargs; + } + } + return NULL; +} + +static void +dump_device_list(void) +{ + struct rte_dpaa2_device *dev; + + /* Only if the log level has been set to Debugging, print list */ + if (rte_log_can_log(dpaa2_logtype_bus, RTE_LOG_DEBUG)) { + DPAA2_BUS_LOG(DEBUG, "List of devices scanned on bus:"); + TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) { + DPAA2_BUS_LOG(DEBUG, "\t\t%s", dev->device.name); + } + } +} + static int scan_one_fslmc_device(char *dev_name) { char *dup_dev_name, *t_ptr; - struct rte_dpaa2_device *dev; + struct rte_dpaa2_device *dev = NULL; + int ret = -1; if (!dev_name) - return -1; + return ret; /* Ignore the Container name itself */ if (!strncmp("dprc", dev_name, 4)) @@ -124,7 +138,7 @@ scan_one_fslmc_device(char *dev_name) /* Creating a temporary copy to perform cut-parse over string */ dup_dev_name = strdup(dev_name); if (!dup_dev_name) { - FSLMC_BUS_LOG(ERR, "Out of memory."); + DPAA2_BUS_ERR("Unable to allocate device name memory"); return -ENOMEM; } @@ -135,15 +149,18 @@ scan_one_fslmc_device(char *dev_name) */ dev = calloc(1, sizeof(struct rte_dpaa2_device)); if (!dev) { - FSLMC_BUS_LOG(ERR, "Out of memory."); + DPAA2_BUS_ERR("Unable to allocate device object"); free(dup_dev_name); return -ENOMEM; } + dev->device.bus = &rte_fslmc_bus.bus; + /* Parse the device name and ID */ t_ptr = strtok(dup_dev_name, "."); if (!t_ptr) { - FSLMC_BUS_LOG(ERR, "Incorrect device string observed."); + DPAA2_BUS_ERR("Invalid device found: (%s)", dup_dev_name); + ret = -EINVAL; goto cleanup; } if (!strncmp("dpni", t_ptr, 4)) @@ -156,26 +173,37 @@ scan_one_fslmc_device(char *dev_name) dev->dev_type = DPAA2_BPOOL; else if (!strncmp("dpio", t_ptr, 4)) dev->dev_type = DPAA2_IO; - else if (!strncmp("dpci", t_ptr, 5)) + else if (!strncmp("dpci", t_ptr, 4)) dev->dev_type = DPAA2_CI; else if (!strncmp("dpmcp", t_ptr, 5)) dev->dev_type = DPAA2_MPORTAL; + else if (!strncmp("dpdmai", t_ptr, 6)) + dev->dev_type = DPAA2_QDMA; + else if (!strncmp("dpdmux", t_ptr, 6)) + dev->dev_type = DPAA2_MUX; + else if (!strncmp("dprtc", t_ptr, 5)) + dev->dev_type = DPAA2_DPRTC; else dev->dev_type = DPAA2_UNKNOWN; t_ptr = strtok(NULL, "."); if (!t_ptr) { - FSLMC_BUS_LOG(ERR, "Incorrect device string observed (%s).", - t_ptr); + DPAA2_BUS_ERR("Skipping invalid device (%s)", dup_dev_name); + ret = 0; goto cleanup; } sscanf(t_ptr, "%hu", &dev->object_id); dev->device.name = strdup(dev_name); if (!dev->device.name) { - FSLMC_BUS_LOG(ERR, "Out of memory."); + DPAA2_BUS_ERR("Unable to clone device name. Out of memory"); + ret = -ENOMEM; goto cleanup; } + dev->device.devargs = fslmc_devargs_lookup(dev); + + /* Update the device found into the device_count table */ + rte_fslmc_bus.device_count[dev->dev_type]++; /* Add device in the fslmc device list */ insert_in_device_list(dev); @@ -190,7 +218,81 @@ cleanup: free(dup_dev_name); if (dev) free(dev); - return -1; + return ret; +} + +static int +rte_fslmc_parse(const char *name, void *addr) +{ + uint16_t dev_id; + char *t_ptr; + const char *sep; + uint8_t sep_exists = 0; + int ret = -1; + + DPAA2_BUS_DEBUG("Parsing dev=(%s)", name); + + /* There are multiple ways this can be called, with bus:dev, name=dev + * or just dev. In all cases, the 'addr' is actually a string. + */ + sep = strchr(name, ':'); + if (!sep) { + /* check for '=' */ + sep = strchr(name, '='); + if (!sep) + sep_exists = 0; + else + sep_exists = 1; + } else + sep_exists = 1; + + /* Check if starting part if either of 'fslmc:' or 'name=', separator + * exists. + */ + if (sep_exists) { + /* If either of "fslmc" or "name" are starting part */ + if (!strncmp(name, RTE_STR(FSLMC_BUS_NAME), + strlen(RTE_STR(FSLMC_BUS_NAME))) || + (!strncmp(name, "name", strlen("name")))) { + goto jump_out; + } else { + DPAA2_BUS_DEBUG("Invalid device for matching (%s).", + name); + ret = -EINVAL; + goto err_out; + } + } else + sep = name; + +jump_out: + /* Validate device name */ + if (strncmp("dpni", sep, 4) && + strncmp("dpseci", sep, 6) && + strncmp("dpcon", sep, 5) && + strncmp("dpbp", sep, 4) && + strncmp("dpio", sep, 4) && + strncmp("dpci", sep, 4) && + strncmp("dpmcp", sep, 5) && + strncmp("dpdmai", sep, 6) && + strncmp("dpdmux", sep, 6)) { + DPAA2_BUS_DEBUG("Unknown or unsupported device (%s)", sep); + ret = -EINVAL; + goto err_out; + } + + t_ptr = strchr(sep, '.'); + if (!t_ptr || sscanf(t_ptr + 1, "%hu", &dev_id) != 1) { + DPAA2_BUS_ERR("Missing device id in device name (%s)", sep); + ret = -EINVAL; + goto err_out; + } + + if (addr) + strcpy(addr, sep); + + ret = 0; +err_out: + return ret; } static int @@ -205,8 +307,7 @@ rte_fslmc_scan(void) int groupid; if (process_once) { - FSLMC_BUS_LOG(DEBUG, - "Fslmc bus already scanned. Not rescanning"); + DPAA2_BUS_DEBUG("Fslmc bus already scanned. Not rescanning"); return 0; } process_once = 1; @@ -216,16 +317,15 @@ rte_fslmc_scan(void) goto scan_fail; /* Scan devices on the group */ - sprintf(fslmc_dirpath, "%s/%d/devices", VFIO_IOMMU_GROUP_PATH, - groupid); + sprintf(fslmc_dirpath, "%s/%s", SYSFS_FSL_MC_DEVICES, fslmc_container); dir = opendir(fslmc_dirpath); if (!dir) { - FSLMC_BUS_LOG(ERR, "Unable to open VFIO group dir."); + DPAA2_BUS_ERR("Unable to open VFIO group directory"); goto scan_fail; } while ((entry = readdir(dir)) != NULL) { - if (entry->d_name[0] == '.' || entry->d_type != DT_LNK) + if (entry->d_name[0] == '.' || entry->d_type != DT_DIR) continue; ret = scan_one_fslmc_device(entry->d_name); @@ -236,9 +336,12 @@ rte_fslmc_scan(void) device_count += 1; } - FSLMC_BUS_LOG(INFO, "fslmc: Bus scan completed"); - closedir(dir); + + DPAA2_BUS_INFO("FSLMC Bus scan completed"); + /* If debugging is enabled, device list is dumped to log output */ + dump_device_list(); + return 0; scan_fail_cleanup: @@ -247,7 +350,7 @@ scan_fail_cleanup: /* Remove all devices in the list */ cleanup_fslmc_device_list(); scan_fail: - FSLMC_BUS_LOG(DEBUG, "FSLMC Bus Not Available. Skipping."); + DPAA2_BUS_DEBUG("FSLMC Bus Not Available. Skipping (%d)", ret); /* Irrespective of failure, scan only return success */ return 0; } @@ -266,6 +369,8 @@ static int rte_fslmc_probe(void) { int ret = 0; + int probe_all; + struct rte_dpaa2_device *dev; struct rte_dpaa2_driver *drv; @@ -274,16 +379,48 @@ rte_fslmc_probe(void) ret = fslmc_vfio_setup_group(); if (ret) { - FSLMC_BUS_LOG(ERR, "Unable to setup VFIO %d", ret); + DPAA2_BUS_ERR("Unable to setup VFIO %d", ret); return 0; } + /* Map existing segments as well as, in case of hotpluggable memory, + * install callback handler. + */ + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + ret = rte_fslmc_vfio_dmamap(); + if (ret) { + DPAA2_BUS_ERR("Unable to DMA map existing VAs: (%d)", + ret); + /* Not continuing ahead */ + DPAA2_BUS_ERR("FSLMC VFIO Mapping failed"); + return 0; + } + } + ret = fslmc_vfio_process_group(); if (ret) { - FSLMC_BUS_LOG(ERR, "Unable to setup devices %d", ret); + DPAA2_BUS_ERR("Unable to setup devices %d", ret); return 0; } + probe_all = rte_fslmc_bus.bus.conf.scan_mode != RTE_BUS_SCAN_WHITELIST; + + /* In case of PA, the FD addresses returned by qbman APIs are physical + * addresses, which need conversion into equivalent VA address for + * rte_mbuf. For that, a table (a serial array, in memory) is used to + * increase translation efficiency. + * This has to be done before probe as some device initialization + * (during) probe allocate memory (dpaa2_sec) which needs to be pinned + * to this table. + * + * Error is ignored as relevant logs are handled within dpaax and + * handling for unavailable dpaax table too is transparent to caller. + * + * And, the IOVA table is only applicable in case of PA mode. + */ + if (rte_eal_iova_mode() == RTE_IOVA_PA) + dpaax_iova_table_populate(); + TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) { TAILQ_FOREACH(drv, &rte_fslmc_bus.driver_list, next) { ret = rte_fslmc_match(drv, dev); @@ -293,13 +430,35 @@ rte_fslmc_probe(void) if (!drv->probe) continue; - ret = drv->probe(drv, dev); - if (ret) - FSLMC_BUS_LOG(ERR, "Unable to probe.\n"); + if (rte_dev_is_probed(&dev->device)) + continue; + + if (dev->device.devargs && + dev->device.devargs->policy == RTE_DEV_BLACKLISTED) { + DPAA2_BUS_LOG(DEBUG, "%s Blacklisted, skipping", + dev->device.name); + continue; + } + + if (probe_all || + (dev->device.devargs && + dev->device.devargs->policy == + RTE_DEV_WHITELISTED)) { + ret = drv->probe(drv, dev); + if (ret) { + DPAA2_BUS_ERR("Unable to probe"); + } else { + dev->driver = drv; + dev->device.driver = &drv->driver; + } + } break; } } + if (rte_eal_iova_mode() == RTE_IOVA_VA) + dpaa2_virt_mode = 1; + return 0; } @@ -307,16 +466,29 @@ static struct rte_device * rte_fslmc_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, const void *data) { + const struct rte_dpaa2_device *dstart; struct rte_dpaa2_device *dev; - TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) { - if (start && &dev->device == start) { - start = NULL; /* starting point found */ - continue; - } + DPAA2_BUS_DEBUG("Finding a device named %s\n", (const char *)data); + + /* find_device is always called with an opaque object which should be + * passed along to the 'cmp' function iterating over all device obj + * on the bus. + */ - if (cmp(&dev->device, data) == 0) + if (start != NULL) { + dstart = RTE_DEV_TO_FSLMC_CONST(start); + dev = TAILQ_NEXT(dstart, next); + } else { + dev = TAILQ_FIRST(&rte_fslmc_bus.device_list); + } + while (dev != NULL) { + if (cmp(&dev->device, data) == 0) { + DPAA2_BUS_DEBUG("Found device (%s)\n", + dev->device.name); return &dev->device; + } + dev = TAILQ_NEXT(dev, next); } return NULL; @@ -341,29 +513,141 @@ rte_fslmc_driver_unregister(struct rte_dpaa2_driver *driver) fslmc_bus = driver->fslmc_bus; + /* Cleanup the PA->VA Translation table; From whereever this function + * is called from. + */ + if (rte_eal_iova_mode() == RTE_IOVA_PA) + dpaax_iova_table_depopulate(); + TAILQ_REMOVE(&fslmc_bus->driver_list, driver, next); /* Update Bus references */ driver->fslmc_bus = NULL; } +/* + * All device has iova as va + */ +static inline int +fslmc_all_device_support_iova(void) +{ + int ret = 0; + struct rte_dpaa2_device *dev; + struct rte_dpaa2_driver *drv; + + TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) { + TAILQ_FOREACH(drv, &rte_fslmc_bus.driver_list, next) { + ret = rte_fslmc_match(drv, dev); + if (ret) + continue; + /* if the driver is not supporting IOVA */ + if (!(drv->drv_flags & RTE_DPAA2_DRV_IOVA_AS_VA)) + return 0; + } + } + return 1; +} + /* * Get iommu class of DPAA2 devices on the bus. */ static enum rte_iova_mode rte_dpaa2_get_iommu_class(void) { + bool is_vfio_noiommu_enabled = 1; + bool has_iova_va; + + if (TAILQ_EMPTY(&rte_fslmc_bus.device_list)) + return RTE_IOVA_DC; + +#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA return RTE_IOVA_PA; +#endif + + /* check if all devices on the bus support Virtual addressing or not */ + has_iova_va = fslmc_all_device_support_iova(); + +#ifdef VFIO_PRESENT + is_vfio_noiommu_enabled = rte_vfio_noiommu_is_enabled() == true ? + true : false; +#endif + + if (has_iova_va && !is_vfio_noiommu_enabled) + return RTE_IOVA_VA; + + return RTE_IOVA_PA; +} + +static int +fslmc_bus_plug(struct rte_device *dev __rte_unused) +{ + /* No operation is performed while plugging the device */ + return 0; +} + +static int +fslmc_bus_unplug(struct rte_device *dev __rte_unused) +{ + /* No operation is performed while unplugging the device */ + return 0; +} + +static void * +fslmc_bus_dev_iterate(const void *start, const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ + const struct rte_dpaa2_device *dstart; + struct rte_dpaa2_device *dev; + char *dup, *dev_name = NULL; + + if (str == NULL) { + DPAA2_BUS_DEBUG("No device string"); + return NULL; + } + + /* Expectation is that device would be name=device_name */ + if (strncmp(str, "name=", 5) != 0) { + DPAA2_BUS_DEBUG("Invalid device string (%s)\n", str); + return NULL; + } + + /* Now that name=device_name format is available, split */ + dup = strdup(str); + dev_name = dup + strlen("name="); + + if (start != NULL) { + dstart = RTE_DEV_TO_FSLMC_CONST(start); + dev = TAILQ_NEXT(dstart, next); + } else { + dev = TAILQ_FIRST(&rte_fslmc_bus.device_list); + } + + while (dev != NULL) { + if (strcmp(dev->device.name, dev_name) == 0) { + free(dup); + return &dev->device; + } + dev = TAILQ_NEXT(dev, next); + } + + free(dup); + return NULL; } struct rte_fslmc_bus rte_fslmc_bus = { .bus = { .scan = rte_fslmc_scan, .probe = rte_fslmc_probe, + .parse = rte_fslmc_parse, .find_device = rte_fslmc_find_device, .get_iommu_class = rte_dpaa2_get_iommu_class, + .plug = fslmc_bus_plug, + .unplug = fslmc_bus_unplug, + .dev_iterate = fslmc_bus_dev_iterate, }, .device_list = TAILQ_HEAD_INITIALIZER(rte_fslmc_bus.device_list), .driver_list = TAILQ_HEAD_INITIALIZER(rte_fslmc_bus.driver_list), + .device_count = {0}, }; -RTE_REGISTER_BUS(fslmc, rte_fslmc_bus.bus); +RTE_REGISTER_BUS(FSLMC_BUS_NAME, rte_fslmc_bus.bus); +RTE_LOG_REGISTER(dpaa2_logtype_bus, bus.fslmc, NOTICE);